Go语言中执行命令的几种方式
go语言用来执行一个系统的命令相对python来说还是有点复杂的,执行命令是一个非常常见的需求,如调用一个系统命令,启一个exe等,这里分为几种情况,之后统一总结一下。
- 只执行命令,不要输出结果
- 执行命令并且要获取到输出结果
- 阻塞和异步的执行
以下以ping www.baidu.com 为例依次执行一下各种命令,主要使用标准库中的os/exec。
在执行命令的时候,我们主要使用的是os/exec包主的Cmd结构体方法,Cmd的结构体定义如下 Cmd结构体定义[1]。
主要的参数有
- Path string
- // Args保管命令的参数,包括命令名作为第一个参数;如果为空切片或者nil,相当于无参数命令。
- //
- // 典型用法下,Path和Args都应被Command函数设定。
- Args []string
- // Env指定进程的环境,如为nil,则是在当前进程的环境下执行。
- Stdin io.Reader
- // Stdout和Stderr指定进程的标准输出和标准错误输出。
- //
- // 如果任一个为nil,Run方法会将对应的文件描述符关联到空设备(os.DevNull)
- //
- // 如果两个字段相同,同一时间最多有一个线程可以写入。
- Stdout io.Writer
- Stderr io.Writer
但是我们一般不直接构造Cmd结构体,而是通过exec.Command() 函数返回一个Cmd结构体指针 如 exec.Command("ping","www.baidu.com") ping为命令,"www.baidu.com" 为参数,在得到*Cmd以后再使用结构体方法Run,Start等方法来真正的执行命令。
只执行命令,不要输出结果这里的输出结果只是表明命令执行了,但是它具体的输出我们不关心,在这种其实用的挺多的,我们只是想执行命令,在python里我们可以使用os.system() 函数来执行,当然这个是阻塞的执行。
- >>> import os
- >>> r = os.system("ping www.baidu.com")
- 正在 Ping www.a.shifen.com [39.156.66.18] 具有 32 字节的数据:
- 来自 39.156.66.18 的回复: 字节=32 时间=6ms TTL=54
- 来自 39.156.66.18 的回复: 字节=32 时间=28ms TTL=54
- 来自 39.156.66.18 的回复: 字节=32 时间=6ms TTL=54
- 来自 39.156.66.18 的回复: 字节=32 时间=7ms TTL=54
- 39.156.66.18 的 Ping 统计信息:
- 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
- 往返行程的估计时间(以毫秒为单位):
- 最短 = 6ms,最长 = 28ms,平均 = 11ms
- >>> r
- 0
这里的r只是获取了该命令的执行结果,是0表示没有错误,但是执行命令的输出如 正在 Ping www.a.shifen.com..... 我们并不关心。
执行命令可以使用Run() 或者Start() 方法,Run是阻塞的执行,Start() 是非阻塞的执行。
程序什么也没有输出,但是停顿的一段时间后才退出。如果换成command.Start() 则程序运行起来以后马上就停止了。
如果想要获取到像python 那种 os.system的执行结果,其实这里的结果应该是ExitError,程序的退出码,应该怎么操作呢?这里exec包里有一个专门的结构体ExitError,使用它的一些方法可以获取到ExitCode,但是想要获取到ExitCode得到得到命令结束,也就是要阻塞的运行,上面使用Run() 方法可以阻塞等待执行结果,使用Start()方法以后,也可以使用Wait()方法来等待执行结束。
通过
- command.ProcessState.Sys().(syscall.WaitStatus).ExitCode
来获取到命令执行的退出码。
执行命令并且要获取到输出结果这里的输出结果是命令行的标准输出或者错误输出,也就是stdout或者stderr,通过bytes.Buffer来存储。
这里得到的中文输出有乱码:
这个我查了一下一般都是说是设置一下控制台输出chcp或者使用:
- golang.org/x/text/encoding/simplifiedchinese
这个包进行转换,我不想使用,这个以后找到方法再说吧。
命令行的输入有时候进入命令行会等待用户的交互,如输入nslookup。
执行不在环境变量里的命令像上面这个ping 命令,由于在windows 或者linux中,这个命令是在环境变量里,但是像windows中的copy 命令,它是不在环境变量里,正常情况下你可以在cmd中使用copy 命令,但是如果在go 语言中如果直接像上面那样使用是不行的。 例如使用上面的代码,替换一下copy 命令。
得到的输出结果为: