Created
August 10, 2017 08:27
-
-
Save matejb/c88bd07c2c36e4ebed31644fbcceac15 to your computer and use it in GitHub Desktop.
simple Go pipe executor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment