marketer
marketer

Reputation: 43677

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

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?

Upvotes: 146

Views: 198582

Answers (8)

Zombo
Zombo

Reputation: 1

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

Upvotes: 6

Inasa Xia
Inasa Xia

Reputation: 501

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
    }
}

Upvotes: 21

Fatih Arslan
Fatih Arslan

Reputation: 17117

There is an easier way now:

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    out, err := exec.Command("date").Output()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("The date is %s\n", out)
}

Where out is the standard output. It's in the format []byte, but you can change it to string easily with:

string(out)

You can also use CombinedOutput() instead of Output() which returns standard output and standard error.

exec.Command

Upvotes: 457

lcapra
lcapra

Reputation: 1540

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")

Upvotes: 6

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))
    }
}

Upvotes: 0

Travis Reeder
Travis Reeder

Reputation: 41103

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())

Upvotes: 71

Andru Luvisi
Andru Luvisi

Reputation: 25318

Use exec.Run, passing Pipe for stdout. Read from the pipe that it returns.

Upvotes: 4

esm
esm

Reputation: 1830

Two options, depending on the paradigm you prefer:

  1. os.ForkExec()
  2. exec.Run()

Upvotes: 4

Related Questions