Dies ist ein voll funktionsfähiges Beispiel. Die Execute
-Funktion nimmt eine beliebige Anzahl von exec.Cmd
Instanzen (unter Verwendung einer variadic function) und führt dann eine Schleife über sie korrekt die Ausgabe von stdout an die stdin des nächsten Befehls. Dies muss geschehen, bevor eine Funktion aufgerufen wird.
Die Anruffunktion und der Sicherstellung der Verschluß von Rohrleitungen
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)
}
In dieser GIST
https://gist.github.com/tyndyll/89fbb2c2273f83a074dc
Eine gute rekursiv aufzurufen, die Befehle in einer Schleife zu rufen, indem aufschiebt dann geht Punkt zu wissen ist, dass Shell-Variablen wie ~ sind nicht interpoliert
Warum verwende ich io.Pipe statt exec.Cmd.StdoutPipe? –
Ich mag io.Pipe auch, aber den C1-Start in eine separate Goroutine zu setzen funktioniert besser für mich. Siehe meine modifizierte Version unten. – WeakPointer