Go中执行外部命令需正确使用exec.Command:Run()适合无需输出的场景;Output()一行获取stdout;Stdin/Stdout/Stderr管道实现细粒度控制;须防shell注入、设超时、控环境变量与工作目录。

使用 os/exec 包执行外部命令是 Go 中很常见的需求,核心在于正确创建、配置并运行 *exec.Cmd 实例。关键不是“能不能跑”,而是“怎么控制输入输出、捕获错误、避免阻塞、防止 shell 注入”。
基础执行:Run() 最简调用
Run() 适合不需要读取输出、只关心命令是否成功的情况(比如 git commit、cp)。
- 它会自动等待命令结束,返回
error(非零退出码也会转为 error) - 标准输入/输出/错误都继承自当前进程(即打印到终端)
- 不推荐用于需要获取输出的场景
示例:
```gocmd := exec.Command("ls", "-l", "/tmp")
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
```
获取输出:Output() 一行拿回 stdout
Output() 自动重定向 stdout 到内存,返回 []byte 和 error,适合简单命令如 date、hostname、cat file。
立即学习“go语言免费学习笔记(深入)”;
- stderr 不被捕获,仍输出到终端(除非显式重定向)
- 命令超时或崩溃会返回 error,stdout 内容可能为空
- 注意大输出可能吃内存,慎用于
find / | head -1000类命令
示例:
```goout, err := exec.Command("date").Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out)) // 输出类似 "Wed Jun 12 10:24:33 CST 2024\n"
```
细粒度控制:Stdin/Stdout/Stderr 手动接管
当需要实时处理流、双向通信、或分别捕获 stdout/stderr 时,用 StdinPipe、StdoutPipe、StderrPipe。
- 必须在
Start()前调用 Pipe 方法,否则 panic -
Start()启动命令但不等待,之后可读写管道、再调用Wait() - 常见组合:用
bytes.Buffer或io.MultiWriter收集输出
示例(捕获 stdout + stderr 分开):
```gocmd := exec.Command("sh", "-c", `echo "hello"; echo "world" >&2`)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Println("stdout:", stdout.String()) // "hello\n"
fmt.Println("stderr:", stderr.String()) // "world\n"
```
安全与实用细节
绕不开的几个实际问题:
-
别拼接字符串传给 Command:避免 shell 注入。用
exec.Command("grep", "-r", userInput, "."),而不是exec.Command("sh", "-c", "grep -r '"+userInput+"' .") -
设置超时:用
context.WithTimeout传给CommandContext,比手动 goroutine + timer 更可靠 -
环境变量控制:修改
cmd.Env可覆盖或添加环境变量(默认继承 os.Environ) -
工作目录:设置
cmd.Dir指定执行路径
带超时的完整示例:
```goctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "sleep", "10")
err := cmd.Run()
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
fmt.Println("command timed out")
} else {
log.Fatal(err)
}
}
```
基本上就这些。用对 Run/Output/Start+Wait 三种模式,再注意安全和超时,90% 的外部命令需求都能稳稳拿下。










