Golangで、外部コマンド実行
2011/07/10
前回Golangをバージョンアップした時動かなくなったexec周りのメモです。
Golangで何かをやろうとして、実装方法がわからない時、最初に当たるのは、公式のリファレンスです。
これは結構しっかり書いてあるんですが、使用例が書いてないので、どう使うのが正しいのかわからない 時があります。検索しても、新しい言語であるせいか、あまりサンプルコードが見付からないです。 そんな時は、Golangのソースに添付されているテストコードと、実際のソースコードを見ることになります。
最初に実装した時(release.r57.1 8294)も、exec周りのソースコードを見て外部コマンド実行ができるように なったんですが、今回見たら(release.r58 8731)、悲しいくらいexec関連のインターフェースが変わっていたので、 新しいインターフェースでの外部コマンド実行のコードをメモしておきます。
main.go
package main
import (
"os"
"io"
"log"
"exec"
)
func RunCommand(command string, args []string, environ []string) {
cmd := exec.Command(command)
cmd.Env = environ
cmd.Args = args
cmd.Dir = "."
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal("failed to retrieve pipe. %s", err)
os.Exit(-1)
}
err = cmd.Start()
if err != nil {
log.Fatal("failed to execute external command. %s", err)
os.Exit(-1)
}
WriteFileStream(stdout)
}
func WriteFileStream(reader io.Reader) {
var (
err os.Error
n int
)
buf := make([]byte, 1024)
for {
if n, err = reader.Read(buf); err != nil {
break
}
log.Print(string(buf[0:n]))
}
if err == os.EOF {
log.Println("stdout end");
err = nil
} else {
log.Println("ERROR: " + err.String());
}
}
func main() {
environ := os.Environ()
command := "/bin/ping"
args := []string {command, "-c", "5", "localhost"}
RunCommand(command, args, environ)
} |
今回やりたかったのは、バックグラウンドで外部コマンドを実行しつつ、流れてくる 標準出力を取得することでした。cmd.StdoutPipe()で取得したio.Readerから、 WriteFileStreamで、標準出力を受けとり次第、ログ出力してます。 最初、buf変数を要素数を指定せずに定義してたところ、標準出力を取ろうとすると、すぐos.EOFが 返ってきて、取得できなかったのですが、makeで領域を確保する形で定義するように変更したところ、 正しく標準出力を取得できました。
Makefile
default: main.go
6g main.go
6l -o runcommand main.6
run: default
./runcommand |
実行結果
$ ./runcommand 2011/07/11 03:03:27 PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.048 ms 2011/07/11 03:03:28 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.042 ms 2011/07/11 03:03:29 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.041 ms 2011/07/11 03:03:30 64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.041 ms 2011/07/11 03:03:31 64 bytes from localhost (127.0.0.1): icmp_seq=5 ttl=64 time=0.042 ms 2011/07/11 03:03:31 2011/07/11 03:03:31 --- localhost ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 3996ms rtt min/avg/max/mdev = 0.041/0.042/0.048/0.008 ms 2011/07/11 03:03:31 stdout end |