package main import ( "bytes" "fmt" "log" "os/exec" "strings" ) func main() { out, err := pipe("ls -l | grep io | wc -l") if err != nil { log.Println(err) } fmt.Println(out) } func pipe(line string) (output string, err error) { cmds := strings.Split(line, "|") lastIx := len(cmds) - 1 var outputBuf bytes.Buffer type chainLink struct { info string wait *exec.Cmd execute *exec.Cmd } chain := make([]chainLink, 0, len(cmds)) // make chain for ix := range cmds { cmd := strings.TrimSpace(cmds[ix]) cmdArgs := strings.Split(cmd, " ") link := chainLink{ info: cmd, execute: exec.Command(cmdArgs[0], cmdArgs[1:]...), } if ix > 0 { // link out to in prevOut, err := chain[ix-1].execute.StdoutPipe() if err != nil { return "", fmt.Errorf("failed getting previous stdout on %q: %s", chain[ix-1].info, err) } link.execute.Stdin = prevOut // add wait for previous cmd link.wait = chain[ix-1].execute } if ix == lastIx { // last one writes to buffer link.execute.Stdout = &outputBuf } chain = append(chain, link) } // execute chain var link chainLink for { link, chain = chain[0], chain[1:] if err := link.execute.Start(); err != nil { return "", fmt.Errorf("failed starting on %q: %s", link.info, err) } if link.wait != nil { if err := link.wait.Wait(); err != nil { return "", fmt.Errorf("failed waiting for previous on %q: %s", link.info, err) } } if len(chain) == 0 { if err := link.execute.Wait(); err != nil { return "", fmt.Errorf("failed waiting on %q: %s", link.info, err) } return outputBuf.String(), nil } } }