当前位置: 首页 > news >正文

Go 语言 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)

packagemainimport("fmt""os/exec")funcmain(){// Linux/macOScmd:=exec.Command("echo","hello go exec")// Windows: cmd := exec.Command("cmd", "/c", "echo hello go exec")output,err:=cmd.Output()iferr!=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()iferr!=nil{fmt.Println("执行失败:",err)}

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

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

packagemainimport("io""os""os/exec")funcmain(){// Linux/macOScmd:=exec.Command("ping","192.168.0.1","-c","3")// Windows: exec.Command("ping", "192.168.0.1", "-n", "3")stdout,err:=cmd.StdoutPipe()iferr!=nil{panic(err)}cmd.Stderr=os.Stderr// 错误直接输出iferr:=cmd.Start();err!=nil{panic(err)}// 实时读取输出io.Copy(os.Stdout,stdout)// 等待命令结束iferr:=cmd.Wait();err!=nil{panic(err)}}
  • Start():异步启动
  • Wait():等待子进程退出
  • io.Copy:实时流输出

五、给命令传输入(Stdin)

向子进程输入内容:

packagemainimport("os/exec""strings")funcmain(){// 将字符串作为标准输入传给 catcmd:=exec.Command("cat")cmd.Stdin=strings.NewReader("我是输入内容\nhello exec")output,err:=cmd.CombinedOutput()iferr!=nil{panic(err)}println(string(output))}

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

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

七、带超时的安全调用

防止命令卡死:

packagemainimport("context""os/exec""time")funcmain(){// 5秒超时ctx,cancel:=context.WithTimeout(context.Background(),5*time.Second)defercancel()// 传入ctxcmd:=exec.CommandContext(ctx,"sleep","10")err:=cmd.Run()iferr!=nil{// 超时会返回 ctx 错误println("命令结束:",err)}}

八、获取退出码

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

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

九、坑点

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

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

    正确:

    exec.Command("echo","hello","world")
  2. Windows 要调用 cmd /c

    exec.Command("cmd","/c","dir")
  3. 输出乱码
    Windows 下命令多为 GBK,需要转码。

packagemainimport("bytes""io""os/exec""golang.org/x/text/encoding/simplifiedchinese""golang.org/x/text/transform")funcmain(){// Windows 执行 ipconfigcmd:=exec.Command("ipconfig")varbuf bytes.Buffer// 输出:GBK → UTF-8cmd.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 可能导致死锁
    输出缓冲区满会阻塞子进程,程序卡住。

packagemainimport("os/exec")// 这个程序会 100% 卡死!funcmain(){// 生成大量输出的命令// 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)}
http://www.jsqmd.com/news/433536/

相关文章:

  • 从STM32开发日志到技术文档:EVA-02的嵌入式应用场景
  • 【数字人语音合成实战】Windows系统下Fun-CosyVoice3-0.5B-2512从零部署到避坑指南
  • BetterNCM-Installer实战指南:从环境适配到深度定制的全流程解析
  • 2026北京狗狗寄养专业正规合规机构推荐及详细介绍 - 品牌2026
  • QuickLook.Plugin.OfficeViewer-Native:重新定义Office文件预览体验的效率工具
  • 高性能人脸检测开源镜像:cv_resnet101_face-detection_cvpr22papermogface GPU利用率提升300%实测
  • 告别手动听歌打卡:网易云音乐自动播放解决方案实现每日300首播放量自动化
  • 2026年初至今,阜阳靠谱软体家具厂家综合实力评估 - 2026年企业推荐榜
  • 2026年武汉二手货架市场深度剖析与优质服务商甄选指南 - 2026年企业推荐榜
  • GTE文本向量模型效果展示:高维向量可视化分析
  • 官宣 | Apache Fluss (Incubating) 0.9 发布公告
  • 2026北京狗狗寄养推荐+优质机构详解 - 品牌2026
  • 霜儿-汉服-造相Z-Turbo开发环境配置:基于IDEA的Java调用示例详解
  • 2026年阜阳床垫厂家评测:谁才是可靠之选? - 2026年企业推荐榜
  • LTSC系统微软商店一键恢复:解决专业版应用生态缺失痛点
  • 次元画室学术应用:使用LaTeX排版AI生成的艺术论文插图
  • CentOS本地部署Whisper模型实战:从环境配置到性能调优
  • rt-thread入门之旅(二)—— 从rt_kprintf看RT-Thread的设备驱动框架
  • 微信单向好友如何高效识别?WechatRealFriends带来的社交关系管理新体验
  • 2026年3月叉车槽钢公司大揭秘,哪家才是优选,桥梁贝雷片/无缝方管/Q345D方矩管/Q355B方管,槽钢公司口碑推荐 - 品牌推荐师
  • 5倍效率颠覆传统剪辑:Autocut语义驱动视频生产的实战指南
  • Keyviz深度应用指南:从核心价值到进阶技巧
  • BERT文本分割-中文-通用领域实操手册:上传文档→设置参数→获取结果
  • MusePublic开源镜像免配置部署指南:GPU显存优化+安全过滤一体化
  • 构建AI绘画工具:集成cv_unet_image-colorization与Stable Diffusion的图像处理管线
  • gte-base-zh中文Embedding效果对比:gte-base-zh vs. bge-zh vs. m3e实测
  • Wan2.1 VAE创意延展:使用LaTeX排版自动生成论文插图
  • Qwen2-VL-2B-Instruct实战案例:电商主图A/B测试中图文一致性评估
  • 跨越公网与内网:Ubuntu 22 LTS 上 EVE-NG 混合云部署与多端口精细化管理实战
  • 软件授权管理:IDM试用期延长的系统化解决方案