Đây là một ví dụ làm việc đầy đủ. Hàm Execute
mất bất kỳ số lượng exec.Cmd
trường hợp nào (sử dụng variadic function) và sau đó lặp lại chúng một cách chính xác khi gắn kết đầu ra của stdout vào stdin của lệnh tiếp theo. Điều này phải được thực hiện trước khi bất kỳ hàm nào được gọi.
Chức năng cuộc gọi sau đó đi về gọi các lệnh trong một vòng lặp, sử dụng trì hoãn để gọi đệ quy và đảm bảo việc đóng cửa đúng đắn của đường ống
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)
}
Có sẵn trong ý chính này
https://gist.github.com/tyndyll/89fbb2c2273f83a074dc
Một tốt điểm cần biết là các biến hệ vỏ như ~ không được nội suy
Tại sao sử dụng io.Pipe thay vì exec.Cmd.StdoutPipe? –
Tôi thích io.Pipe quá, nhưng việc bắt đầu c1 vào một goroutine riêng biệt hoạt động tốt hơn cho tôi. Xem phiên bản đã sửa đổi của tôi bên dưới. – WeakPointer