有时候项目需要实现一个类似shell脚本的功能,让开发项目自身程序类型以外的其他脚本程序(或者编译后程序)来根据情况执行,这个时候不会python怎么办?go语言可以帮助我们实现。先写一些linux下shell命令的例子:
package main import( "fmt" "io/ioutil" "os/exec" ) func main() { // 从一个简单的命令开始 这个命令不需要任何参数 // 或者输入,仅仅向stdout输出一些信息,使用包里面的exec.Command dateCmd := exec.Command("date") // Output 是另一个运行命令时用来处理信息的函数,这个函数等待命令结束,然后收集命令输出,如果没有错误发生的话, // dateOut 将保存date的信息 dateOut, err := dateCmd.Output() if err != nil { panic(err) } fmt.Println("> date") fmt.Println(string(dateOut)) // 下面我们看一个需要从stdin输入数据的命令, 我们将数据输入传给外部进程stdin // 然后从它输出到stdout的运行结果收集信息 grepCmd := exec.Command("grep", "hello") // 这里我们显式地获取input/output管道,启动进程,向进程写入数据,然后读取输出结果,最后等待进程结束 grepIn, _ := grepCmd.StdinPipe() grepOut, _ := grepCmd.StdoutPipe() grepCmd.Start() grepIn.Write([]byte("hello grep\ngoodbye grep")) grepIn.Close() grepBytes, _ := ioutil.ReadAll(grepOut) grepCmd.Wait() // 在上面的例子中,我开门忽略了错误检测,但是你一样可以使用 if err!=nil 这种模式来进行处理, // 另外,我们仅仅收集了stdoutPipe 的结果,同时你也可以用一样的方法来收集StderrPipe的结果 fmt.Println("> grep hello") fmt.Println(string(grepBytes)) // 注意,在触发外部命令的时候,需要显式地提供命令和参数信息 // 另外如果你想用一个命令行字符串触发一个完整的命令, 你可以使用bash的一个-c选项 lsCmd := exec.Command("bash", "-c", "ls -a -l -h") lsOut, err := lsCmd.Output() if err != nil { panic(err) } fmt.Println("> ls -a -l -h") fmt.Println(string(lsOut)) }
所触发的程序执行结果和我们直接执行这些程序的结果是一样的, 运行结果:
> date Sat Dec 8 11:18:35 PDT 2017 > grep hello hello grep > ls -a -l -h drwxr-xr-x 4 qinchao 136B Dec 3 10:10 . drwxr-xr-x 91 qinchao 3.0K Dec 3 10:10 .. -rw-r--r-- 1 qinchao 138K Dec 3 10:10 spawning-processes.go
一些新手遇到比较复杂连续的shell命令, 上来可能就开心地写了以下的代码
xxCmd := exec.Command("chmod -R 755 /root/sample") xxOut, err := xxCmd.Output() if err != nil { panic(err) }
发现会报错误no such file or directory
这里纠正一下, 你首先要传入bash执行路径作为第一个参数, 第二个参数传入bash的执行参数, 一般都是-c, 最后的第三个参数才是传shell指令。所以面对以上这种报错解决方式, 应该这样写:
// 加入/bin/bash和-c作为前两个参数 xxCmd := exec.Command("/bin/bash", "-c", "chmod -R 777 /root/sample") xxOut, err := xxCmd.Output() if err != nil { panic(err) }