欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang應(yīng)用執(zhí)行Shell命令實戰(zhàn)

 更新時間:2023年03月16日 09:47:20   作者:夢想畫家  
本文主要介紹了Golang應(yīng)用執(zhí)行Shell命令實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

本文學習如何在Golang程序中執(zhí)行Shell命令(如,ls,mkdir或grep),如何通過stdin和stdout傳入I/O給正在運行的命令,同時管理長時間運行的命令。為了更好的理解,針對不同場景由淺入深提供幾個示例進行說明,希望你能輕松理解。

exec包

使用官方os/exec包可以執(zhí)行外部命令,當你執(zhí)行shell命令,是需要在Go應(yīng)用的外部運行代碼,因此需要這些命令在子進程中運行。如下圖所示:

在這里插入圖片描述

每個命令在Go應(yīng)用中作為子進程運行,并暴露stdin和stdout屬性,我們可以使用它們讀寫進程數(shù)據(jù)。

運行基本Shell命令

運行簡單命令并從它的輸出中讀取數(shù)據(jù),通過創(chuàng)建*exec.Cmd實例實現(xiàn)。在下面示例中,使用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,程序沒有產(chǎn)生shell,而是直接運行給定命令,這意味著不會進行任何基于shell的處理,比如glob模式或擴展。舉例,當運行ls ./*.md命令,并不會如我們在那個shell中運行命令一樣輸出readme.md。

執(zhí)行長時間運行命令

前面示例執(zhí)行l(wèi)s命令立刻返回結(jié)果,但當命令輸出是連續(xù)的、或需要很長時間執(zhí)行時會怎樣呢?舉例,運行ping命令,會周期性獲得連續(xù)結(jié)果:

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執(zhí)行這類命令,則不會獲得任何結(jié)果,因為Output方法等待命令執(zhí)行結(jié)束,而ping無限期執(zhí)行。因此需要自定義Stdout屬性去讀取連續(xù)輸出:

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)
}

再次運行程序,輸出結(jié)果于Shell中執(zhí)行類似。

通過直接分配Stdout屬性,我們可以在整個命令生命周期中捕獲輸出,并在接收到輸出后立即對其進行處理。進程間io交互如下圖所示:

在這里插入圖片描述

自定義寫輸出

代替使用os.Stdout,還能通過實現(xiàn)io.Writer接口創(chuàng)建自定義寫輸出。

下面自定義代碼在每個輸出塊前增加"received output: "前綴:

type customOutput struct{}

func (c customOutput) Write(p []byte) (int, error) {
	fmt.Println("received output: ", string(p))
	return len(p), nil
}

現(xiàn)在給命令輸出賦值自定義寫輸出實例:

cmd.Stdout = customOutput{}

再次運行程序,會獲得下面的輸出。

使用Stdin給命令傳遞輸入

前面示例沒有給命令任何輸入(或提供有限輸入作為參數(shù)),大多數(shù)場景中通過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)
}

輸出結(jié)果:

3. apple

在這里插入圖片描述

結(jié)束子進程

有一些命令無限期運行,需要能夠顯示信號去結(jié)束。舉例,如果使用python3 -m http.server運行web服務(wù)或sleep 10000,則子進程會運行很長時間或無限期運行。

要停止進程,需要從應(yīng)用中發(fā)送kill信號,可以通過給命令增加上下文實例實現(xiàn)。如果上下文取消,則命令也會終止執(zhí)行:

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秒后輸出結(jié)果:

could not run command:  signal: killed
Output:  

當需要在有限時間內(nèi)運行命令或在一定時間內(nèi)命令沒有返回結(jié)果則執(zhí)行備用邏輯。

總結(jié)

到目前為止,我們已經(jīng)學習了多種執(zhí)行unix shell命令和與之交互的方法。下面是使用os/exec包時需要注意的一些事情:

  • 當您希望執(zhí)行通常不提供太多輸出的簡單命令時使用cmd.Output
  • 對于具有連續(xù)或長時間輸出的函數(shù)應(yīng)使用cmd.Run,并通過cmd.Stdout和cmd.Stdin與之交互
  • 在生產(chǎn)場景中,如果進程在給定時間內(nèi)沒有響應(yīng),須有超時并結(jié)束功能,可以使用取消上下文發(fā)送終止命令

到此這篇關(guān)于Golang應(yīng)用執(zhí)行Shell命令實戰(zhàn)的文章就介紹到這了,更多相關(guān)Golang執(zhí)行Shell命令內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang異常處理之defer,panic,recover的使用詳解

    Golang異常處理之defer,panic,recover的使用詳解

    這篇文章主要為大家介紹了Go語言異常處理機制中defer、panic和recover三者的使用方法,文中示例代碼講解詳細,需要的朋友可以參考下
    2022-05-05
  • Golang實現(xiàn)深拷貝reflect原理示例探究

    Golang實現(xiàn)深拷貝reflect原理示例探究

    這篇文章主要為大家介紹了Golang實現(xiàn)reflect深拷貝原理示例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • 深入了解Golang官方container/list原理

    深入了解Golang官方container/list原理

    在?Golang?的標準庫?container?中,包含了幾種常見的數(shù)據(jù)結(jié)構(gòu)的實現(xiàn),其實是非常好的學習材料,本文主要為大家介紹了container/list的原理與使用,感興趣的可以了解一下
    2023-08-08
  • Go語言遍歷目錄的三種方法舉例

    Go語言遍歷目錄的三種方法舉例

    學習io之后,尤其是文件操作,我們就可以遍歷給定的目錄了,這篇文章主要給大家介紹了關(guān)于Go語言遍歷目錄的三種方法,分別是ioutil.ReadDir、filepath.Walk以及filepath.Glob,需要的朋友可以參考下
    2023-11-11
  • GoLang調(diào)用鏈可視化go-callvis使用介紹

    GoLang調(diào)用鏈可視化go-callvis使用介紹

    與鏈路追蹤(Tracing)不同,Tracing關(guān)注復(fù)雜的分布式環(huán)境中各個服務(wù)節(jié)點間的調(diào)用關(guān)系,主要用于服務(wù)治理。而我們本次探索的代碼調(diào)用鏈路則是代碼方法級別的調(diào)用關(guān)系,主要用于代碼設(shè)計
    2023-02-02
  • golang如何實現(xiàn)mapreduce單進程版本詳解

    golang如何實現(xiàn)mapreduce單進程版本詳解

    這篇文章主要給大家介紹了關(guān)于golang如何實現(xiàn)mapreduce單進程版本的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2018-01-01
  • go語言通過zlib壓縮數(shù)據(jù)的方法

    go語言通過zlib壓縮數(shù)據(jù)的方法

    這篇文章主要介紹了go語言通過zlib壓縮數(shù)據(jù)的方法,實例分析了Go語言中zlib的使用技巧,需要的朋友可以參考下
    2015-03-03
  • golang的os包用法詳解

    golang的os包用法詳解

    Go語言的 os 包中提供了操作系統(tǒng)函數(shù)的接口,是一個比較重要的包。顧名思義,os 包的作用主要是在服務(wù)器上進行系統(tǒng)的基本操作,本文將詳細介紹了golang的os包用法,需要的朋友可以參考下
    2023-05-05
  • Golang Mutex互斥鎖深入理解

    Golang Mutex互斥鎖深入理解

    這篇文章主要為大家介紹了Golang Mutex互斥鎖深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Golang 語言map底層實現(xiàn)原理解析

    Golang 語言map底層實現(xiàn)原理解析

    這篇文章主要介紹了Golang 語言map底層實現(xiàn)原理解析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12

最新評論