有時候項目需要實現一個類似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)
}