如何在Go中pipe几个命令?
我怎样才能在Go中input几个外部命令? 我试过这个代码,但我得到一个错误,说exit status 1
。
package main import ( "io" "log" "os" "os/exec" ) func main() { c1 := exec.Command("ls") stdout1, err := c1.StdoutPipe() if err != nil { log.Fatal(err) } if err = c1.Start(); err != nil { log.Fatal(err) } if err = c1.Wait(); err != nil { log.Fatal(err) } c2 := exec.Command("wc", "-l") c2.Stdin = stdout1 stdout2, err := c2.StdoutPipe() if err != nil { log.Fatal(err) } if err = c2.Start(); err != nil { log.Fatal(err) } if err = c2.Wait(); err != nil { log.Fatal(err) } io.Copy(os.Stdout, stdout2) }
当命令启动时,StdoutPipe返回一个将连接到命令标准输出的pipe道。 看到命令退出后,pipe道将自动closures。
(来自http://golang.org/pkg/os/exec/#Cmd.StdinPipe )
你做的事实c1.Wait
closuresstdoutPipe
。
我做了一个工作的例子(只是一个演示,添加错误捕捉!):
package main import ( "bytes" "io" "os" "os/exec" ) func main() { c1 := exec.Command("ls") c2 := exec.Command("wc", "-l") r, w := io.Pipe() c1.Stdout = w c2.Stdin = r var b2 bytes.Buffer c2.Stdout = &b2 c1.Start() c2.Start() c1.Wait() w.Close() c2.Wait() io.Copy(os.Stdout, &b2) }
对于简单的场景,你可以使用这种方法:
bash -c "echo 'your command goes here'"
例如,此函数使用pipe道命令检索CPU型号名称:
func getCPUmodel() string { cmd := "cat /proc/cpuinfo | egrep '^model name' | uniq | awk '{print substr($0, index($0,$4))}'" out, err := exec.Command("bash","-c",cmd).Output() if err != nil { return fmt.Sprintf("Failed to execute command: %s", cmd) } return string(out) }
package main import ( "os" "os/exec" ) func main() { c1 := exec.Command("ls") c2 := exec.Command("wc", "-l") c2.Stdin, _ = c1.StdoutPipe() c2.Stdout = os.Stdout _ = c2.Start() _ = c1.Run() _ = c2.Wait() }
就像第一个答案一样,但第一个命令开始并在一个公用事业中等待。 这使pipe道快乐。
package main import ( "io" "os" "os/exec" ) func main() { c1 := exec.Command("ls") c2 := exec.Command("wc", "-l") pr, pw := io.Pipe() c1.Stdout = pw c2.Stdin = pr c2.Stdout = os.Stdout c1.Start() c2.Start() go func() { defer pw.Close() c1.Wait() }() c2.Wait() }
这是一个完全可行的例子。 Execute
函数使用任意数量的exec.Cmd
实例(使用可变参数函数 ),然后正确地将stdout的输出附加到下一个命令的stdin上。 这必须在任何函数被调用之前完成。
然后调用函数继续调用循环中的命令,使用recursionrecursion调用并确保正确closurespipe道
package main import ( "bytes" "io" "log" "os" "os/exec" ) func Execute(output_buffer *bytes.Buffer, stack ...*exec.Cmd) (err error) { var error_buffer bytes.Buffer pipe_stack := make([]*io.PipeWriter, len(stack)-1) i := 0 for ; i < len(stack)-1; i++ { stdin_pipe, stdout_pipe := io.Pipe() stack[i].Stdout = stdout_pipe stack[i].Stderr = &error_buffer stack[i+1].Stdin = stdin_pipe pipe_stack[i] = stdout_pipe } stack[i].Stdout = output_buffer stack[i].Stderr = &error_buffer if err := call(stack, pipe_stack); err != nil { log.Fatalln(string(error_buffer.Bytes()), err) } return err } func call(stack []*exec.Cmd, pipes []*io.PipeWriter) (err error) { if stack[0].Process == nil { if err = stack[0].Start(); err != nil { return err } } if len(stack) > 1 { if err = stack[1].Start(); err != nil { return err } defer func() { if err == nil { pipes[0].Close() err = call(stack[1:], pipes[1:]) } }() } return stack[0].Wait() } func main() { var b bytes.Buffer if err := Execute(&b, exec.Command("ls", "/Users/tyndyll/Downloads"), exec.Command("grep", "as"), exec.Command("sort", "-r"), ); err != nil { log.Fatalln(err) } io.Copy(os.Stdout, &b) }
可用在这个要点
https://gist.github.com/tyndyll/89fbb2c2273f83a074dc
要知道的一点是,像〜这样的shellvariables不是插值的