• Go中调用外部命令的几种姿势


    引子

    在工作中,我时不时地会需要在Go中调用外部命令。前段时间我做了一个工具,在钉钉群中添加了一个机器人,@这个机器人可以让它执行一些写好的脚本程序完成指定的任务。机器人倒是不难,照着钉钉开发者文档添加好机器人,然后@这个机器人就会向一个你指定的服务器发送一个POST请求,请求中会附带文本消息。所以我要做的就是搭一个Web服务器,可以用go原生的net/http包,也可以用gin/fasthttp/fiber这些Web框架。收到请求之后,检查附带文本中的关键字去调用对应的程序,然后返回结果。

    go标准库中的os/exec包对调用外部程序提供了支持,本文详细介绍os/exec的使用姿势。

    运行命令

    Linux中有个cal命令,它可以显示指定年、月的日历,如果不指定年、月,默认为当前时间对应的年月。如果使用的是Windows,推荐安装msys2,这个软件包含了绝大多数的Linux常用命令。

    24ce8d0d386d7a5a183e3963d4b27e8d.png

    297bf2ca0202ab8aed89a32bcb2222d7.png

    那么,在Go代码中怎么调用这个命令呢?其实也很简单:

    1. func main() {
    2.   cmd := exec.Command("cal")
    3.   err := cmd.Run()
    4.   if err != nil {
    5.     log.Fatalf("cmd.Run() failed: %v\n", err)
    6.   }
    7. }

    首先,我们调用exec.Command传入命令名,创建一个命令对象exec.Cmd。接着调用该命令对象的Run()方法运行它。

    如果你实际运行了,你会发现什么也没有发生,哈哈。事实上,使用os/exec执行命令,标准输出和标准错误默认会被丢弃。

    显示输出

    exec.Cmd对象有两个字段StdoutStderr,类型皆为io.Writer。我们可以将任意实现了io.Writer接口的类型实例赋给这两个字段,继而实现标准输出和标准错误的重定向。io.Writer接口在 Go 标准库和第三方库中随处可见,例如*os.File*bytes.Buffernet.Conn。所以我们可以将命令的输出重定向到文件、内存缓存甚至发送到网络中。

    显示到标准输出

    exec.Cmd对象的StdoutStderr这两个字段都设置为os.Stdout,那么输出内容都将显示到标准输出:

    1. func main() {
    2.   cmd := exec.Command("cal")
    3.   cmd.Stdout = os.Stdout
    4.   cmd.Stderr = os.Stderr
    5.   err := cmd.Run()
    6.   if err != nil {
    7.     log.Fatalf("cmd.Run() failed: %v\n", err)
    8.   }
    9. }

    运行程序。我在git bash运行,得到如下结果:

    a80f634a212a6ad1fec63a4a48df6227.png

    输出了中文,检查一下环境变量LANG的值,果然是zh_CN.UTF-8。如果想输出英文,可以将环境变量LANG设置为en_US.UTF-8

    1. $ echo $LANG
    2. zh_CN.UTF-8
    3. $ LANG=en_US.UTF-8 go run main.go

    得到输出:

    6d1a2fdb73d391916d2a05451a420584.png

    输出到文件

    打开或创建文件,然后将文件句柄赋给exec.Cmd对象的StdoutStderr这两个字段即可实现输出到文件的功能。

    1. func main() {
    2.   f, err := os.OpenFile("out.txt", os.O_WRONLY|os.O_CREATE, os.ModePerm)
    3.   if err != nil {
    4.     log.Fatalf("os.OpenFile() failed: %v\n", err)
    5.   }
    6.   cmd := exec
  • 相关阅读:
    pip修改位于用户目录下的缓存目录
    PHP NBA球迷俱乐部系统Dreamweaver开发mysql数据库web结构php编程计算机网页
    (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
    C++设计模式---单例模式
    有趣的前端面试题
    《HCIP-openEuler实验指导手册》1.3Apache动态功能模块加载卸载练习
    【Python】Labelme/PIL读取图片朝向错误解决
    asp.net core webapi接收application/x-www-form-urlencoded和form-data参数
    【Java 进阶篇】使用 SQL 进行排序查询
    虚拟化技术 - I/O虚拟化 [二]
  • 原文地址:https://blog.csdn.net/darjun/article/details/127644250