How do you get the output of a system command in Go?

Viewed 129443

Let's say I want to run 'ls' in a go program, and store the results in a string. There seems to be a few commands to fork processes in the exec and os packages, but they require file arguments for stdout, etc. Is there a way to get the output as a string?

8 Answers

To get both stdout and stderr into separate strings, you can use byte buffers like so:

cmd := exec.Command("date")
var outb, errb bytes.Buffer
cmd.Stdout = &outb
cmd.Stderr = &errb
err := cmd.Run()
if err != nil {
    log.Fatal(err)
}
fmt.Println("out:", outb.String(), "err:", errb.String())
cmd := exec.Command("ls", "-al")
output, _ := cmd.CombinedOutput()
fmt.Println(string(output))

or

cmd := exec.Command(name, arg...)
stdout, err := cmd.StdoutPipe()
cmd.Stderr = cmd.Stdout
if err != nil {
    return err
}
if err = cmd.Start(); err != nil {
    return err
}
for {
    tmp := make([]byte, 1024)
    _, err := stdout.Read(tmp)
    fmt.Print(string(tmp))
    if err != nil {
        break
    }
}

I used this with a recent version of GO (~1.11)

// CmdExec Execute a command
func CmdExec(args ...string) (string, error) {

    baseCmd := args[0]
    cmdArgs := args[1:]

    log.Debugf("Exec: %v", args)

    cmd := exec.Command(baseCmd, cmdArgs...)
    out, err := cmd.Output()
    if err != nil {
        return "", err
    }

    return string(out), nil
}

// Usage:
// out, err := CmdExec("ls", "/home")

Edit: This answer is obsolete. Please see Fatih Arslan's answer below.


Use exec.Run by specifying Pipe as the stdout (and stderr if you want). It will return cmd, which contains an os.File in the Stdout (and Stderr) fields. Then you can read it using for example ioutil.ReadAll.

Example:

package main

import (
    "exec";
    "io/ioutil";
)

func main() {
    if cmd, e := exec.Run("/bin/ls", nil, nil, exec.DevNull, exec.Pipe, exec.MergeWithStdout); e == nil {
        b, _ := ioutil.ReadAll(cmd.Stdout)
        println("output: " + string(b))
    }
}

If you are wanting string output, strings.Builder is more efficient [1] than bytes.Buffer:

package main

import (
   "os/exec"
   "strings"
)

func main() {
   c, b := exec.Command("go", "version"), new(strings.Builder)
   c.Stdout = b
   c.Run()
   print(b.String())
}
  1. https://golang.org/pkg/bytes#Buffer.String
Related