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 |
実行結果
$ ./runcommand2011/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 ms2011/07/11 03:03:28 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.042 ms2011/07/11 03:03:29 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.041 ms2011/07/11 03:03:30 64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.041 ms2011/07/11 03:03:31 64 bytes from localhost (127.0.0.1): icmp_seq=5 ttl=64 time=0.042 ms2011/07/11 03:03:312011/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 ms2011/07/11 03:03:31 stdout end |