Golang os/exec标准库如何执行命令_Golang调用系统命令

7次阅读

exec.Command 安全调用应拆分命令与参数,避免 shell 注入;Output 捕获 stdout 而 stderr 仍输出,CombinedOutput 合并两者;超时和环境变量需在 Start 前设置。

Golang os/exec标准库如何执行命令_Golang调用系统命令

exec.Command 启动命令最安全

直接调用系统 shell(比如 /bin/sh -c)容易引入注入风险,尤其当命令参数来自用户输入时。优先用 exec.Command 拆分命令名和参数,让 go 自己拼接执行,不经过 shell 解析。

例如执行 ls -l /tmp,应该写成:

cmd := exec.Command("ls", "-l", "/tmp") out, err := cmd.Output()

而不是:

cmd := exec.Command("sh", "-c", "ls -l "+userInput) // 危险!
  • 参数必须单独传入,不能拼在字符串
  • 如果真要走 shell(如需要管道、通配符),明确用 sh -c 并严格校验或转义 userInput
  • Command 返回的是未运行的命令对象,需显式调用 RunOutputCombinedOutput

cmd.Output()cmd.CombinedOutput() 区别在哪

Output 只捕获 stdout,stderr 仍会输出到父进程的 stderr;CombinedOutput 把两者都重定向到同一字节切片,适合调试或简单场景。

立即学习go语言免费学习笔记(深入)”;

  • 想分别处理标准输出和错误?用 cmd.StdoutPipe()cmd.StderrPipe() 配合 Start + Wait
  • 只关心成功与否,不关心输出?用 Run,它返回 Error,但不返回任何输出内容
  • Output 在命令失败(非零退出码)时也会返回 error,且 err != nilout 仍可能含 stdout 内容(取决于是否已写入)

设置超时和环境变量必须在 cmd.Start() 前完成

cmd.Wait()cmd.Output() 不会自动带超时;环境变量也必须通过 cmd.Env 设置,不能靠修改 os.Environ() 影响子进程。

cmd := exec.Command("sleep", "10") cmd.Env = append(os.Environ(), "MY_VAR=value") if err := cmd.Start(); err != nil {     log.Fatal(err) } done := make(chan error, 1) go func() { done <- cmd.wait() }() select { case <-time.after(3 * time.second): cmd.process.kill()>

  • cmd.Process.Kill() 是终止进程的正确方式,cmd.Wait() 不会中断正在运行的命令
  • cmd.Env 默认是 os.Environ() 的拷贝,修改它不影响全局环境
  • 超时后务必读取 done 通道,否则 goroutine 泄漏

windows 下路径和可执行文件名要注意扩展名

Windows 不像 unix 系统自动查找 PATHEXT 中的扩展名(如 .exe.bat)。直接写 exec.Command("ping") 在某些环境下可能失败。

  • 显式带上 .exe 更可靠:exec.Command("ping.exe", "-n", "1", "localhost")
  • exec.LookPath("ping") 动态查找完整路径,它会按 PATHEXT 规则搜索
  • 跨平台代码中,避免硬编码路径分隔符,用 filepath.Join 构造命令路径

实际写的时候,最容易被忽略的是:超时后没等 Wait 完成就丢弃进程,导致子进程变成僵尸;还有就是把用户输入直接拼进 sh -c 字符串里,没做任何过滤。

text=ZqhQzanResources