
本文介绍如何在 Go 中使用 exec.Command 同时将子进程的标准输出实时显示在控制台,并一次性完整获取全部输出内容(string 或 []byte),避免逐行读取,核心方案是结合 bytes.Buffer 与 io.MultiWriter。
本文介绍如何在 go 中使用 `exec.command` 同时将子进程的标准输出实时显示在控制台,并一次性完整获取全部输出内容(`string` 或 `[]byte`),避免逐行读取,核心方案是结合 `bytes.buffer` 与 `io.multiwriter`。
在 Go 中调用外部命令时,常需兼顾「实时可见性」与「结果可编程处理」:既要像调试时一样看到命令输出流式打印到终端,又希望执行结束后能直接拿到完整输出用于解析、日志记录或文本提取。若仅设置 cmd.Stdout = os.Stdout,则无法后续访问输出;若仅设为 &bytes.Buffer{},又会丢失终端可见性。
此时,io.MultiWriter 是最简洁优雅的解决方案——它允许将写入操作同时分发到多个 io.Writer(如 os.Stdout 和内存缓冲区),无需手动复制或协程同步。
以下是一个完整、健壮的示例:
package main
import (
"bytes"
"io"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("ping", "-c", "3", "google.com") // Linux/macOS 示例;Windows 可用 "ping -n 3 google.com"
var out bytes.Buffer
// 将 stdout 同时写入终端和缓冲区
cmd.Stdout = io.MultiWriter(os.Stdout, &out)
if err := cmd.Run(); err != nil {
log.Fatalf("command failed: %v", err)
}
// 执行完毕后,完整输出已保存在 out 中
fullOutput := out.String()
log.Printf("\n✅ 命令执行完成,共捕获 %d 字符输出:", len(fullOutput))
log.Printf("? 输出摘要:%q", fullOutput[:min(len(fullOutput), 100)])
}
✅ 关键要点说明:
- io.MultiWriter(os.Stdout, &out) 创建一个复合 writer,所有写入均被广播至两者;
- bytes.Buffer 实现了 io.Writer 接口,天然兼容;
- cmd.Run() 阻塞直至命令结束,确保 out.String() 获取的是最终完整输出;
- 不需要额外 goroutine 或 cmd.CombinedOutput()(后者无法实时打印);
- 若还需捕获标准错误(stderr),可同样使用 io.MultiWriter(os.Stderr, &errBuf) 并赋值给 cmd.Stderr。
⚠️ 注意事项:
- 确保命令实际产生输出(例如 ping 在某些系统可能静默失败);
- 对于超长输出,bytes.Buffer 默认无大小限制,但生产环境建议考虑内存用量;
- Windows 下注意命令参数格式差异(如 ping -n 3 而非 -c 3);
- 若需结构化处理(如按行解析),仍可在 out.String() 基础上进一步切分,但本方案保留了原始字节完整性。
综上,io.MultiWriter + bytes.Buffer 组合以最小侵入性、最高可读性,完美满足“边看边存”的典型运维与自动化场景需求。











