Go语言exec包的具体使用

 更新时间:2026年06月01日 15:03:14   作者:石牌桥网管  
在Go中执行外部命令、调用系统程序,核心就是使用标准库os/exec,它能启动进程、传递参数、读写输入输出、控制超时,是脚本化、自动化、调用第三方工具的必备能力,下面就来详细的介绍一下

在 Go 中执行外部命令、调用系统程序,核心就是使用标准库 os/exec。它能启动进程、传递参数、读写输入输出、控制超时,是脚本化、自动化、调用第三方工具的必备能力。

本文实例讲解 exec 包常用用法。

一、exec 包核心概念

os/exec 用于创建和控制子进程,与直接系统调用不同:

  • 自带安全处理,不会自动注入 Shell,更安全
  • 支持分离 Stdout/Stderr/Stdin
  • 可等待、杀死、设置超时、获取退出码
  • 多平台通用

常用结构与函数:

  • exec.Command(name, arg...):创建命令对象
  • cmd.Run():运行并等待完成
  • cmd.Output():运行并返回标准输出
  • cmd.CombinedOutput():返回 stdout + stderr
  • cmd.Start() + cmd.Wait():异步启动,异步等待
  • cmd.StdoutPipe():实时读取输出

二、最简单示例:执行命令并获取输出

1. 获取命令输出(Output)

package main

import (
	"fmt"
	"os/exec"
)

func main() {
	// Linux/macOS
	cmd := exec.Command("echo", "hello go exec")
	// Windows: cmd := exec.Command("cmd", "/c", "echo hello go exec")

	output, err := cmd.Output()
	if err != nil {
		fmt.Printf("执行失败: %v\n", err)
		return
	}

	fmt.Printf("输出结果: %s\n", output)
}
  • Output() 会在命令非0退出码时返回错误
  • 返回的 output[]byte,直接转字符串即可

2. 获取 stdout + stderr(CombinedOutput)

当需要把日志和错误一起收集时使用:

output, err := cmd.CombinedOutput()

三、只运行不获取输出(Run)

只关心命令是否成功,不关心输出:

cmd := exec.Command("sleep", "1")
err := cmd.Run()
if err != nil {
	fmt.Println("执行失败:", err)
}

四、实时输出(不等待缓冲区满)

以前遇到过坑:命令输出很长时,Output() 会阻塞
正确做法是用管道实时读取:

package main

import (
	"io"
	"os"
	"os/exec"
)

func main() {
	// Linux/macOS 
	cmd := exec.Command("ping", "192.168.0.1", "-c", "3")
	// Windows: exec.Command("ping", "192.168.0.1", "-n", "3")

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		panic(err)
	}
	cmd.Stderr = os.Stderr // 错误直接输出

	if err := cmd.Start(); err != nil {
		panic(err)
	}

	// 实时读取输出
	io.Copy(os.Stdout, stdout)

	// 等待命令结束
	if err := cmd.Wait(); err != nil {
		panic(err)
	}
}
  • Start():异步启动
  • Wait():等待子进程退出
  • io.Copy:实时流输出

五、给命令传输入(Stdin)

向子进程输入内容:

package main

import (
	"os/exec"
	"strings"
)

func main() {
	// 将字符串作为标准输入传给 cat
	cmd := exec.Command("cat")
	cmd.Stdin = strings.NewReader("我是输入内容\nhello exec")

	output, err := cmd.CombinedOutput()
	if err != nil {
		panic(err)
	}
	println(string(output))
}

六、设置工作目录、环境变量

cmd := exec.Command("ls")
cmd.Dir = "/tmp"          // 工作目录
cmd.Env = []string{       // 环境变量
	"PATH=/usr/bin:/bin",
	"MY_ENV=test",
}

七、带超时的安全调用

防止命令卡死:

package main

import (
	"context"
	"os/exec"
	"time"
)

func main() {
	// 5秒超时
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 传入ctx
	cmd := exec.CommandContext(ctx, "sleep", "10")

	err := cmd.Run()
	if err != nil {
		// 超时会返回 ctx 错误
		println("命令结束:", err)
	}
}

八、获取退出码

Go 没有直接返回 ExitCode(),需要类型断言:

if err != nil {
	if exitErr, ok := err.(*exec.ExitError); ok {
		fmt.Println("退出码:", exitErr.ExitCode())
	}
}

九、坑点

不要手动拼接命令字符串
错误:

exec.Command("echo hello world") // 错

正确:

exec.Command("echo", "hello", "world")

Windows 要调用 cmd /c

exec.Command("cmd", "/c", "dir")

输出乱码
Windows 下命令多为 GBK,需要转码。

package main

import (
	"bytes"
	"io"
	"os/exec"

	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
)

func main() {
	// Windows 执行 ipconfig
	cmd := exec.Command("ipconfig")

	var buf bytes.Buffer
	// 输出:GBK → UTF-8
	cmd.Stdout = transform.NewWriter(&buf, simplifiedchinese.GBK.NewDecoder())
	cmd.Stderr = transform.NewWriter(&buf, simplifiedchinese.GBK.NewDecoder())

	_ = cmd.Run()
	println(buf.String()) // 中文不乱码
}
  1. Output() 会阻塞
    大量输出必须用 StdoutPipe 实时消费。

  2. 不处理 Stdout/Stderr 可能导致死锁
    输出缓冲区满会阻塞子进程,程序卡住。

package main

import (
	"os/exec"
)

// 这个程序会 100% 卡死!
func main() {
	// 生成大量输出的命令
	// Windows: cmd /c "echo 大量行&for /L %i in (1,1,5000) do @echo 这是一行测试数据"
	cmd := exec.Command("cmd", "/c", "echo 大量行&for /L %i in (1,1,5000) do @echo 这是一行测试数据")

	// 关键错误:不设置 Stdout、Stderr
	// 管道缓冲区会被填满,子进程阻塞,cmd.Run() 永远不返回
	err := cmd.Run()
	println("永远到不了这里", err)
}

到此这篇关于Go语言exec包的具体使用的文章就介绍到这了,更多相关Go语言 exec包内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go新工具gonew生成模板工具链使用详解

    go新工具gonew生成模板工具链使用详解

    这篇文章主要为大家介绍了go新工具gonew生成模板工具链使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • golang实现给图片加水印

    golang实现给图片加水印

    这篇文章主要为大家详细介绍了Vue3如何利用golang实现给图片加水印,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
    2023-12-12
  • 手把手教你用VS code快速搭建一个Golang项目

    手把手教你用VS code快速搭建一个Golang项目

    Go语言是采用UTF8编码的,理论上使用任何文本编辑器都能做Go语言开发,下面这篇文章主要给大家介绍了关于使用VS code快速搭建一个Golang项目的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-04-04
  • Golang标准库unsafe源码解读

    Golang标准库unsafe源码解读

    这篇文章主要为大家介绍了Golang标准库unsafe源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Golang通道的无阻塞读写的方法示例

    Golang通道的无阻塞读写的方法示例

    这篇文章主要介绍了Golang通道的无阻塞读写的方法示例,详细的介绍了哪些情况会存在阻塞,以及如何使用select解决阻塞,非常具有实用价值,需要的朋友可以参考下
    2018-11-11
  • 解决goland新建项目文件名为红色的问题

    解决goland新建项目文件名为红色的问题

    这篇文章主要介绍了解决goland新建项目文件名为红色的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go利用Swag实现将注释转换为专业的API文档

    Go利用Swag实现将注释转换为专业的API文档

    Swag是一个将Go语言注释自动转换为Swagger 2.0文档的工具,支持多种流行Go Web框架,本文我们就来简单讲讲如何使用Swag将简单的代码注释生成专业的API文档的吧
    2025-06-06
  • go语言调用其他包中的函数简单示例

    go语言调用其他包中的函数简单示例

    这篇文章主要给大家介绍了关于go语言调用其他包中的函数的相关资料,文中还介绍了Go语言同一个包中不同文件之间函数调用的相关问题,需要的朋友可以参考下
    2023-01-01
  • 利用golang的字符串解决leetcode翻转字符串里的单词

    利用golang的字符串解决leetcode翻转字符串里的单词

    这篇文章主要介绍了利用golang的字符串解决leetcode翻转字符串里的单词,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • golang中连接mysql数据库

    golang中连接mysql数据库

    这篇文章主要介绍了golang中连接mysql数据库的步骤,帮助大家更好的理解和学习go语言,感兴趣的朋友可以了解下
    2020-12-12

最新评论