โš™๏ธRunning Subprocesses with os/execLESSON

Running Subprocesses with os/exec

Why os/exec?

Go programs often need to shell out to external tools: git, ffmpeg, openssl, database CLI utilities. The os/exec package runs subprocesses safely โ€” without a shell, without injection risks, and with full control over stdin/stdout/stderr.

Running a command and capturing output

Output() runs the command, waits for it to complete, and returns stdout as []byte. If the command exits with a non-zero status, err is *exec.ExitError.

CombinedOutput โ€” stdout + stderr together

Useful when you want the complete output regardless of which stream it came from.

Checking exit codes

Run() runs the command and waits โ€” use it when you don't need the output.

Connecting stdin/stdout/stderr

Assign io.Reader/io.Writer values to cmd.Stdin, cmd.Stdout, cmd.Stderr before calling Run().

Streaming output with pipes

Use StdoutPipe() + cmd.Start() + cmd.Wait() when you need to process output line by line while the command runs.

Security: never use shell=true

Do not construct commands by concatenating user input into a shell string:

exec.Command takes the program name and each argument separately. No shell is invoked โ€” special characters in arguments are passed literally.

Setting environment and working directory

cmd.Dir sets the working directory. cmd.Env replaces the entire environment โ€” start from os.Environ() to inherit the current env, then append overrides.

Context cancellation

exec.CommandContext kills the subprocess when the context is cancelled โ€” essential for server-side use where runaway processes must not outlive their request.

Knowledge Check

Why is exec.Command("sh", "-c", "ls "+userInput) dangerous?

What is the difference between cmd.Output() and cmd.Run()?

When should you use exec.CommandContext instead of exec.Command?