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

8

140

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?

Leatherjacket answered 9/12, 2009 at 21:33 Comment(0)
D
0

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))
    }
}
Doth answered 11/12, 2009 at 6:13 Comment(2)
I don't think the "exec" package exists anymore. I had to use "os/exec" as listed by Fatih below.Acute
Downvote reason: This answer probably is outdated, and wanted people to know about it. exec package no longer exists afaik, ioutil.ReadAll() no longer accepts cmd.Stdout but cmd.Stdin, thus almost everything about this answer is wrong and outdated.Anstice
D
445

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

Defilade answered 4/4, 2013 at 15:41 Comment(3)
This should most likely be the accepted answer now. The accepted answer doesn't even compile anymore.Newfoundland
Useful if you don't need to do anything else with the command (add environment variables, for example).Corked
A go playground with this code: play.golang.org/p/QM4JcIPrxJBLittlefield
M
67

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())
Mccrae answered 10/10, 2016 at 23:27 Comment(0)
V
17
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
    }
}
Villose answered 29/6, 2020 at 3:57 Comment(2)
For an interactive command that I needed to run and read all the output from several times. An interactive command I was running. This helped to see the output, where io.ReadAll did not for reasons unknown to meGamesmanship
Careful! I just learned (using Go 1.19) if you call stdout.Read(tmp) and there is nothing else to read, then it will block. This hit me up for a few hours (sad panda).Gamesmanship
Z
6

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")
Zoa answered 8/2, 2019 at 4:57 Comment(0)
M
4

Two options, depending on the paradigm you prefer:

  1. os.ForkExec()
  2. exec.Run()
Miniaturist answered 10/12, 2009 at 4:28 Comment(0)
B
4

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
Bacillary answered 4/4, 2021 at 21:29 Comment(0)
D
3

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

Dupre answered 9/12, 2009 at 21:44 Comment(1)
That should probably be referred to as exec.Run() (which returns a Cmd), rather than Cmd.Run.Miniaturist
D
0

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))
    }
}
Doth answered 11/12, 2009 at 6:13 Comment(2)
I don't think the "exec" package exists anymore. I had to use "os/exec" as listed by Fatih below.Acute
Downvote reason: This answer probably is outdated, and wanted people to know about it. exec package no longer exists afaik, ioutil.ReadAll() no longer accepts cmd.Stdout but cmd.Stdin, thus almost everything about this answer is wrong and outdated.Anstice

© 2022 - 2025 — McMap. All rights reserved.