您好,登錄后才能下訂單哦!
今天小編給大家分享一下Golang怎么應用執行Shell命令的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
使用官方os/exec包可以執行外部命令,當你執行shell命令,是需要在Go應用的外部運行代碼,因此需要這些命令在子進程中運行。如下圖所示:
每個命令在Go應用中作為子進程運行,并暴露stdin和stdout屬性,我們可以使用它們讀寫進程數據。
運行簡單命令并從它的輸出中讀取數據,通過創建*exec.Cmd實例實現。在下面示例中,使用ls列出當前目錄下的文件,并從代碼中打印其輸出:
// create a new *Cmd instance // here we pass the command as the first argument and the arguments to pass to the command as the // remaining arguments in the function cmd := exec.Command("ls", "./") // The `Output` method executes the command and // collects the output, returning its value out, err := cmd.Output() if err != nil { // if there was any error, print it here fmt.Println("could not run command: ", err) } // otherwise, print the output from running the command fmt.Println("Output: ", string(out))
因為在當前目錄下運行程序,因此輸出項目根目錄下文件:
> go run shellcommands/main.go Output: LICENSE README.md command.go
當運行exec,程序沒有產生shell,而是直接運行給定命令,這意味著不會進行任何基于shell的處理,比如glob模式或擴展。舉例,當運行ls ./*.md
命令,并不會如我們在那個shell中運行命令一樣輸出readme.md
。
前面示例執行ls命令立刻返回結果,但當命令輸出是連續的、或需要很長時間執行時會怎樣呢?舉例,運行ping命令,會周期性獲得連續結果:
ping www.baidu.com PING www.a.shifen.com (36.152.44.95) 56(84) bytes of data. 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=1 ttl=128 time=11.1 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=2 ttl=128 time=58.8 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=3 ttl=128 time=28.2 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=4 ttl=128 time=11.1 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=5 ttl=128 time=11.5 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=6 ttl=128 time=53.6 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=7 ttl=128 time=10.2 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=8 ttl=128 time=10.4 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=9 ttl=128 time=15.8 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=10 ttl=128 time=16.5 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=11 ttl=128 time=10.9 ms ^C64 bytes from 36.152.44.95: icmp_seq=12 ttl=128 time=9.92 ms
如果嘗試使用cmd.Output執行這類命令,則不會獲得任何結果,因為Output方法等待命令執行結束,而ping無限期執行。因此需要自定義Stdout屬性去讀取連續輸出:
cmd := exec.Command("ping", "google.com") // pipe the commands output to the applications // standard output cmd.Stdout = os.Stdout // Run still runs the command and waits for completion // but the output is instantly piped to Stdout if err := cmd.Run(); err != nil { fmt.Println("could not run command: ", err) }
再次運行程序,輸出結果于Shell中執行類似。
通過直接分配Stdout屬性,我們可以在整個命令生命周期中捕獲輸出,并在接收到輸出后立即對其進行處理。進程間io交互如下圖所示:
代替使用os.Stdout,還能通過實現io.Writer接口創建自定義寫輸出。
下面自定義代碼在每個輸出塊前增加"received output: "前綴:
type customOutput struct{} func (c customOutput) Write(p []byte) (int, error) { fmt.Println("received output: ", string(p)) return len(p), nil }
現在給命令輸出賦值自定義寫輸出實例:
cmd.Stdout = customOutput{}
再次運行程序,會獲得下面的輸出。
前面示例沒有給命令任何輸入(或提供有限輸入作為參數),大多數場景中通過Stdin流傳遞輸入信息。典型的示例為grep命令,可以通過管道從一個命令串給另一個命令:
? ~ echo "1. pear\n2. grapes\n3. apple\n4. banana\n" | grep apple 3. apple
這里echo的輸出作為stdin傳給grep,輸入一組水果,通過grep過濾僅輸出apple.
*Cmd實例提供了輸入流用于寫入,下面實例使用它傳遞輸入給grep子進程:
cmd := exec.Command("grep", "apple") // Create a new pipe, which gives us a reader/writer pair reader, writer := io.Pipe() // assign the reader to Stdin for the command cmd.Stdin = reader // the output is printed to the console cmd.Stdout = os.Stdout go func() { defer writer.Close() // the writer is connected to the reader via the pipe // so all data written here is passed on to the commands // standard input writer.Write([]byte("1. pear\n")) writer.Write([]byte("2. grapes\n")) writer.Write([]byte("3. apple\n")) writer.Write([]byte("4. banana\n")) }() if err := cmd.Run(); err != nil { fmt.Println("could not run command: ", err) }
輸出結果:
3. apple
有一些命令無限期運行,需要能夠顯示信號去結束。舉例,如果使用python3 -m http.server
運行web服務或sleep 10000
,則子進程會運行很長時間或無限期運行。
要停止進程,需要從應用中發送kill信號,可以通過給命令增加上下文實例實現。如果上下文取消,則命令也會終止執行:
ctx := context.Background() // The context now times out after 1 second // alternately, we can call `cancel()` to terminate immediately ctx, _ = context.WithTimeout(ctx, 1*time.Second) // sleep 10 second cmd := exec.CommandContext(ctx, "sleep", "10") out, err := cmd.Output() if err != nil { fmt.Println("could not run command: ", err) } fmt.Println("Output: ", string(out))
運行程序,1秒后輸出結果:
could not run command: signal: killed
Output:
當需要在有限時間內運行命令或在一定時間內命令沒有返回結果則執行備用邏輯。
以上就是“Golang怎么應用執行Shell命令”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。