概要
よく忘れるのでメモメモ。
Go の os/exec
パッケージには、コマンドを実行する exec.Command()
がありますが、これを使用して
cmd = exec.Command("ls", "-l", "*.go")
みたいな実行をするとエラーになってしまいます。
シェルの展開を利用したい場合は、まずシェルを起動して、そこからシェルに実行してもらう必要があります。
cmd = exec.Command("/bin/bash", "-c", "ls -l *.go")
こんな感じ。
サンプル
package cmdexec import ( "bufio" "bytes" "errors" "os/exec" "runtime" "github.com/devlights/gomy/output" ) // OneShot は、コマンドを一発実行して結果を取得するサンプルです. // // REFERENCES: // - https://stackoverflow.com/questions/19847594/how-to-reliably-detect-os-platform-in-go // - https://github.com/devlights/try-golang/issues/87 // - https://stackoverflow.com/questions/31467153/golang-failed-exec-command-that-works-in-terminal // - https://github.com/github/hub/blob/2e002395b6a23fd2f51b9ed46e7d7581acd9dbd1/cmd/cmd.go#L40 func OneShot() error { if runtime.GOOS == "windows" { return errors.New("this example cannot run on Windows, sorry") } const ( Shell = "/bin/bash" ) var ( cmd *exec.Cmd // コマンド out []byte // 実行結果 err error // 実行時エラー ) // // シェルの展開が必要ない場合は以下のようにそのまま指定して実行できる // out, _ = exec.Command("pwd").Output() output.Stdoutl("pwd", string(out)) cmd = exec.Command("ls", "-l") out, err = cmd.Output() if err != nil { return err } output.Stdoutf("ls -l", "\n%s", string(out)) output.StdoutHr() // // シェルの展開が必要な場合は sh -c または bash -c のようにシェル起動後にコマンド実行してもらう // cmd = exec.Command(Shell, "-c", "ls -l go.*") out, err = cmd.Output() if err != nil { return err } output.Stdoutf("ls -l go.*", "\n%s", string(out)) output.StdoutHr() // // シェル起動後の実行は 普段のコマンド実行 と変わりない。パイプも指定できる // cmd = exec.Command(Shell, "-c", "ls -l | tail -n 3") out, err = cmd.Output() if err != nil { return err } output.Stdoutf("ls -l | tail -n 3", "\n%s", string(out)) output.StderrHr() // // 結果は []byte で取得できているので、後で好きに加工できる // var ( scanner = bufio.NewScanner(bytes.NewReader(out)) lastline string ) for scanner.Scan() { lastline = scanner.Text() } if err := scanner.Err(); err != nil { return err } output.Stdoutl("last line", lastline) return nil }
try-golang/oneshot.go at master · devlights/try-golang · GitHub
実行すると以下のようになります。
codespace ➜ /workspaces/try-golang (master) $ make run go get -d ./... go run -race github.com/devlights/try-golang/cmd/trygolang -onetime -example "" ENTER EXAMPLE NAME: cmdexec_oneshot [Name] "cmdexec_oneshot" pwd /workspaces/try-golang ls -l total 52 drwxrwxrwx+ 4 codespace root 4096 Mar 29 14:08 cmd -rw-rw-rw- 1 codespace root 207 Mar 29 14:08 Dockerfile -rw-rw-rw- 1 codespace root 810 Mar 29 14:08 go.mod -rw-rw-rw- 1 codespace root 20341 Mar 29 14:08 go.sum drwxrwxrwx+ 6 codespace root 4096 Mar 29 14:08 internal -rw-rw-rw- 1 codespace root 1071 Mar 29 14:08 LICENSE -rw-rw-rw- 1 codespace root 2147 Mar 29 14:08 Makefile drwxrwxrwx+ 3 codespace root 4096 Mar 29 14:08 pkg -rw-rw-rw- 1 codespace root 1466 Mar 29 14:08 README.md -------------------------------------------------- ls -l go.* -rw-rw-rw- 1 codespace root 810 Mar 29 14:08 go.mod -rw-rw-rw- 1 codespace root 20341 Mar 29 14:08 go.sum -------------------------------------------------- ls -l | tail -n 3 -rw-rw-rw- 1 codespace root 2147 Mar 29 14:08 Makefile drwxrwxrwx+ 3 codespace root 4096 Mar 29 14:08 pkg -rw-rw-rw- 1 codespace root 1466 Mar 29 14:08 README.md -------------------------------------------------- last line -rw-rw-rw- 1 codespace root 1466 Mar 29 14:08 README.md [Elapsed] 10.816446ms
参考資料
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場