Skip to content
shellhacks.dev
Go

Run a command and capture output

Run a command and capture its output in Go with exec.Command(...).Output(). On failure the error is an *exec.ExitError that carries the stderr text.

1 min read
Summarize in AI

A Go program needs to run another command and read what it printed, including the error message when it fails.

main.goGo
package main

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

func main() {
	out, err := exec.Command("echo", "hello").Output()
	fmt.Printf("out=%q err=%v\n", out, err)

	_, err = exec.Command("ls", "/nonexistent").Output()
	var ee *exec.ExitError
	if errors.As(err, &ee) {
		fmt.Printf("exit=%d stderr=%q\n", ee.ExitCode(), ee.Stderr)
	}
}
Shell
go run main.go
Text
out="hello\n" err=<nil>
exit=2 stderr="ls: cannot access '/nonexistent': No such file or directory\n"

Output runs the command, waits and returns what it wrote to standard output. If the command exits non-zero, the error is an *exec.ExitError, and when Stderr was not set Output fills the error's Stderr field with the beginning of what the command wrote there, as the os/exec documentation states. ExitCode gives the status. No shell is involved, so the arguments are passed exactly as written.

There is no shell, so pipes, globs and ~ in the arguments are not expanded. Use exec.Command("sh", "-c", ...) when you need them, and never put user input in that string. Only the first part of stderr is kept in the error, so set cmd.Stderr yourself when you need all of it.

Share

More snippets

Go

Exit with a status

Exit with a status using os.Exit(n). It ends the program at once and skips every deferred call, so cleanup in defer is not run before the exit.

1 min read
Go

Raise the scanner line limit

Raise the line limit of bufio.Scanner with Buffer(make([]byte, 0, 64*1024), max). Lines over 64 KB otherwise stop the scan with token too long.

1 min read
Go

Set a timeout for a command

Stop a command that takes too long with exec.CommandContext and context.WithTimeout. In Go 1.19 a shell's child can keep Output() waiting past the deadline.

2 min read

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.