Skip to main content
Sometimes your Go programs need to spawn other processes. Go provides the os/exec package to create and manage external processes.

Basic Command Execution

The simplest way to run an external command is to use exec.Command followed by the Output method.
import (
    "fmt"
    "os/exec"
)

// Create a command that runs date
dateCmd := exec.Command("date")

// Run the command and collect output
dateOut, err := dateCmd.Output()
if err != nil {
    panic(err)
}
fmt.Println("> date")
fmt.Println(string(dateOut))
The exec.Command helper creates an object to represent the external process. The Output method runs the command, waits for it to finish, and collects its standard output.

Error Handling

The exec package provides specific error types for different failure scenarios:

exec.Error

Returned when there’s a problem executing the command (e.g., wrong path)

exec.ExitError

Returned when the command runs but exits with a non-zero return code
_, err = exec.Command("date", "-x").Output()
if err != nil {
    if e, ok := errors.AsType[*exec.Error](err); ok {
        fmt.Println("failed executing:", e)
    } else if e, ok := errors.AsType[*exec.ExitError](err); ok {
        exitCode := e.ExitCode()
        fmt.Println("command exit rc =", exitCode)
    } else {
        panic(err)
    }
}

Piping Input and Output

For more complex scenarios, you can pipe data to a process’s stdin and collect results from stdout:
grepCmd := exec.Command("grep", "hello")

// Get input/output pipes
grepIn, _ := grepCmd.StdinPipe()
grepOut, _ := grepCmd.StdoutPipe()

// Start the process
grepCmd.Start()

// Write input
grepIn.Write([]byte("hello grep\ngoodbye grep"))
grepIn.Close()

// Read output
grepBytes, _ := io.ReadAll(grepOut)
grepCmd.Wait()

fmt.Println("> grep hello")
fmt.Println(string(grepBytes))
1

Create pipes

Use StdinPipe() and StdoutPipe() to get input/output streams
2

Start the process

Call Start() to begin execution without waiting
3

Communicate

Write to stdin and read from stdout
4

Wait for completion

Call Wait() to ensure the process finishes
You can also collect StderrPipe in exactly the same way as StdoutPipe.

Spawning Full Command Strings

When you need to run a complete command string (instead of separate command and arguments), use bash with the -c option:
lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
lsOut, err := lsCmd.Output()
if err != nil {
    panic(err)
}
fmt.Println("> ls -a -l -h")
fmt.Println(string(lsOut))
When spawning commands, you need to provide an explicitly delineated command and argument array. You cannot just pass in one command-line string directly to exec.Command.

Example Output

$ go run spawning-processes.go
> date
Thu 05 May 2022 10:10:12 PM PDT

command exit rc = 1
> grep hello
hello grep

> ls -a -l -h
drwxr-xr-x  4 mark 136B Oct 3 16:29 .
drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
-rw-r--r--  1 mark 1.3K Oct 3 16:28 spawning-processes.go

Execing Processes

Replace the current process with another one

Signals

Handle Unix signals in your programs

Build docs developers (and LLMs) love