Skip to content

Instantly share code, notes, and snippets.

@kjk
Created March 11, 2020 22:43
Show Gist options
  • Save kjk/7cca5f1526b2785e03febc16542b96ea to your computer and use it in GitHub Desktop.
Save kjk/7cca5f1526b2785e03febc16542b96ea to your computer and use it in GitHub Desktop.
package main
// https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html
import (
"fmt"
"io"
"log"
"os"
"os/exec"
"runtime"
"sync"
)
func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
var out []byte
buf := make([]byte, 1024, 1024)
for {
n, err := r.Read(buf[:])
if n > 0 {
d := buf[:n]
out = append(out, d...)
_, err := w.Write(d)
if err != nil {
return out, err
}
}
if err != nil {
// Read returns io.EOF at the end of file, which is not an error for us
if err == io.EOF {
err = nil
}
return out, err
}
}
}
func main() {
cmd := exec.Command("ls", "-lah")
if runtime.GOOS == "windows" {
cmd = exec.Command("tasklist")
}
var stdout, stderr []byte
var errStdout, errStderr error
stdoutIn, _ := cmd.StdoutPipe()
stderrIn, _ := cmd.StderrPipe()
err := cmd.Start()
if err != nil {
log.Fatalf("cmd.Start() failed with '%s'\n", err)
}
// cmd.Wait() should be called only after we finish reading
// from stdoutIn and stderrIn.
// wg ensures that we finish
var wg sync.WaitGroup
wg.Add(1)
go func() {
stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn)
wg.Done()
}()
stderr, errStderr = copyAndCapture(os.Stderr, stderrIn)
wg.Wait()
err = cmd.Wait()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
if errStdout != nil || errStderr != nil {
log.Fatal("failed to capture stdout or stderr\n")
}
outStr, errStr := string(stdout), string(stderr)
fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment