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

在Golang中執(zhí)行Shell命令的教程詳解

 更新時間:2023年05月22日 10:57:37   作者:宇宙之一粟  
在本教程中,我們將學(xué)習如何在 Golang 中執(zhí)行shell命令(如 ls、mkdir 或 grep ),我們還將學(xué)習如何通過 stdin 和 stdout 傳遞 I/O 到正在運行的命令,以及管理長時間運行的命令,感興趣的同學(xué)可以借鑒一下

Exec 包

我們可以使用官方的 os/exec 包來運行外部命令。

當我們執(zhí)行 shell 命令時,我們是在 Go 應(yīng)用程序之外運行代碼。為此,我們需要在子進程中運行這些命令。

每個命令都作為正在運行的 Go 應(yīng)用程序中的子進程運行,并公開我們可以用來從進程讀取和寫入數(shù)據(jù)的 Stdin 和 Stdout 屬性。

運行基本的 Shell 命令

要運行一個簡單的命令并讀取其輸出,我們可以創(chuàng)建一個新的 *exec.Cmd 實例并運行它。在此示例中,讓我們使用 ls 列出當前目錄中的文件,并打印代碼的輸出:

// 創(chuàng)建了一個新的 *Cmd 實例
// 使用 "ls" 命令和 "./" 參數(shù)作為參數(shù)
cmd := exec.Command("ls", "./")

// 使用 `Output` 方法執(zhí)行該命令并收集其輸出
out, err := cmd.Output()
if err != nil {
  // 如果執(zhí)行命令時出現(xiàn)錯誤,則輸出錯誤信息
  fmt.Println("could not run command: ", err)
}
// 否則,輸出運行該命令的輸出結(jié)果
fmt.Println("Output: ", string(out))

由于我在示例倉庫中運行此代碼,因此它會打印項目根目錄中的文件:

> go run shellcommands/main.go

Output:  LICENSE
README.md
go.mod
shellcommands

請注意,當我們運行 exec 時,我們的應(yīng)用程序不會生成 shell,而是直接運行給定的命令。這意味著將不會執(zhí)行任何基于 shell 的處理,例如 glob 模式或擴展。

執(zhí)行持久運行的命令

前面的示例執(zhí)行了 ls 命令,該命令立即返回了它的輸出。那些輸出是連續(xù)的,或者需要很長時間才能檢索的命令呢?

例如,當我們運行 ping 命令時,我們會定期獲得連續(xù)輸出:

?  ~ ping google.com
PING google.com (142.250.77.110): 56 data bytes
64 bytes from 142.250.77.110: icmp_seq=0 ttl=116 time=11.397 ms
64 bytes from 142.250.77.110: icmp_seq=1 ttl=116 time=17.646 ms  ## this is received after 1 second
64 bytes from 142.250.77.110: icmp_seq=2 ttl=116 time=10.036 ms  ## this is received after 2 seconds
64 bytes from 142.250.77.110: icmp_seq=3 ttl=116 time=9.656 ms   ## and so on
# ...

如果我們嘗試使用 cmd.Output 執(zhí)行此類型的命令,我們將不會得到任何輸出,因為 Output 方法等待命令執(zhí)行,而 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)
}

這段代碼使用 Go 語言的 exec 包來執(zhí)行 ping 命令并將輸出重定向到標準輸出流(os.Stdout)。具體來說,它創(chuàng)建了一個命令對象(cmd),該對象包含要執(zhí)行的命令(“ping"和"google.com”)。然后將命令的標準輸出流(cmd.Stdout)設(shè)置為應(yīng)用程序的標準輸出流(os.Stdout)。最后,使用 cmd.Run() 方法運行該命令,并等待其完成。如果運行命令時出現(xiàn)錯誤,將在控制臺輸出錯誤信息。

輸出結(jié)果:

> go run shellcommands/main.go
PING google.com (142.250.195.142): 56 data bytes
64 bytes from 142.250.195.142: icmp_seq=0 ttl=114 time=9.397 ms
64 bytes from 142.250.195.142: icmp_seq=1 ttl=114 time=37.398 ms
64 bytes from 142.250.195.142: icmp_seq=2 ttl=114 time=34.050 ms
64 bytes from 142.250.195.142: icmp_seq=3 ttl=114 time=33.272 ms
# ...
# and so on

通過直接分配 Stdout 屬性,我們可以捕獲整個命令生命周期的輸出,并在收到后立即處理。

自定義輸出寫入程序

與使用 os.Stdout 不同,我們可以創(chuàng)建實現(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)在我們可以指定一個新的 customWriter 實例作為輸出寫入器:

cmd.Stdout = customOutput{}

如果我們現(xiàn)在運行應(yīng)用程序,我們將得到以下輸出:

received output:  PING google.com (142.250.195.142): 56 data bytes
64 bytes from 142.250.195.142: icmp_seq=0 ttl=114 time=187.825 ms
received output:  64 bytes from 142.250.195.142: icmp_seq=1 ttl=114 time=19.489 ms
received output:  64 bytes from 142.250.195.142: icmp_seq=2 ttl=114 time=117.676 ms
received output:  64 bytes from 142.250.195.142: icmp_seq=3 ttl=114 time=57.780 ms

使用 STDIN 將輸入傳遞給命令

在前面的示例中,我們在不提供任何輸入(或提供有限的輸入作為參數(shù))的情況下執(zhí)行命令。在大多數(shù)情況下,輸入是通過 STDIN 流給出的。

譯注:就是外部給命令,然后去執(zhí)行

一個著名的例子是 grep 命令,我們可以通過管道從另一個命令輸入:

?  ~ echo "1. pear\n2. grapes\n3. apple\n4. banana\n" | grep apple
3. apple

在這里,輸入通過 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

Kill 一個子進程

有幾個命令會無限期地運行,或者需要明確的信號才能停止。

例如,如果我們使用 python3 -m http.server 啟動 Web 服務(wù)器或執(zhí)行 sleep 10000,則生成的子進程將運行很長時間(或無限運行)。

要停止這些進程,我們需要從應(yīng)用程序發(fā)送終止信號。我們可以通過向命令添加一個上下文實例來做到這一點。

如果上下文被取消,命令也會終止。

ctx := context.Background()
// The context now times out after 1 second
// alternately, we can call `cancel()` to terminate immediately
ctx, cancel = context.WithTimeout(ctx, 1*time.Second)

cmd := exec.CommandContext(ctx, "sleep", "100")

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:  

當您想要限制運行命令所花費的時間或想要創(chuàng)建回退以防命令未按時返回結(jié)果時,終止子進程很有用。

總結(jié)

到目前為止,我們學(xué)習了多種執(zhí)行 unix shell 命令并與之交互的方法。使用 os/exec 包時需要注意以下幾點:

  • 當您想要執(zhí)行通常不會提供太多輸出的簡單命令時,請使用 cmd.Output
  • 對于具有連續(xù)或長時間運行輸出的函數(shù),您應(yīng)該使用 cmd.Run 并使用 cmd.Stdout 和 cmd.Stdin 與命令交互
  • 在生產(chǎn)應(yīng)用程序中,如果某個進程在給定的時間內(nèi)沒有響應(yīng),那么保持超時并終止該進程是非常有用的。我們可以使用上下文取消發(fā)送終止命令。

如果您想了解更多關(guān)于不同功能和配置選項的信息,可以查看官方文檔頁面。

以上就是在Golang中執(zhí)行Shell命令的教程詳解的詳細內(nèi)容,更多關(guān)于Golang執(zhí)行Shell 命令的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 簡單聊一聊Go語言中的數(shù)組和切片

    簡單聊一聊Go語言中的數(shù)組和切片

    數(shù)組和切片由于語法十分相似,在使用中容易混淆,要認真區(qū)分,下面這篇文章主要給大家介紹了關(guān)于Go語言中數(shù)組和切片的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • golang grpc配置使用實戰(zhàn)

    golang grpc配置使用實戰(zhàn)

    本文主要介紹了golang grpc配置使用實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2023-05-05
  • 通過案例詳細聊聊Go語言的變量與常量

    通過案例詳細聊聊Go語言的變量與常量

    在任何一門現(xiàn)代的高級語言中,變量和常量都是它非?;A(chǔ)的程序結(jié)構(gòu)的組成部分,下面這篇文章主要給大家介紹了關(guān)于如何通過案例詳細聊聊Go語言的變量與常量的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • Go實現(xiàn)用戶每日限額的方法(例一天只能領(lǐng)三次福利)

    Go實現(xiàn)用戶每日限額的方法(例一天只能領(lǐng)三次福利)

    這篇文章主要介紹了Go實現(xiàn)用戶每日限額的方法(例一天只能領(lǐng)三次福利)
    2022-01-01
  • GO語言的map類型實例詳解

    GO語言的map類型實例詳解

    這篇文章主要介紹了GO語言的map類型實例詳解,包括對map的創(chuàng)建,賦值,排序,刪除,等操作需要的朋友可以參考下
    2022-12-12
  • go語言中decimal的用法詳解

    go語言中decimal的用法詳解

    本文主要介紹了go語言中decimal的用法詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2023-03-03
  • 一文帶你掌握Golang基礎(chǔ)之通道

    一文帶你掌握Golang基礎(chǔ)之通道

    在Java中,多線程之間的通信方式有哪些?記得嗎?Java多線程間通信的解決方案有很多種,比如:synchronized。在go中,就一種:通道,文中介紹的非常詳細,感興趣的同學(xué)可以參考下
    2023-05-05
  • 深入了解Golang的map增量擴容

    深入了解Golang的map增量擴容

    這篇文章主要介紹了深入了解Golang的map增量擴容,擴容的主要目的是為了縮短map容器的響應(yīng)時間。增量擴容的本質(zhì)其實就是將總的擴容時間分攤到了每一次hash操作上,更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-06-06
  • Go語言建議多使用切片少使用數(shù)組原理探究

    Go語言建議多使用切片少使用數(shù)組原理探究

    這篇文章主要為大家介紹了Go語言建議多使用切片少使用數(shù)組原理探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • Go1.18新特性之泛型使用三步曲(小結(jié))

    Go1.18新特性之泛型使用三步曲(小結(jié))

    本文主要介紹了Go1.18新特性之泛型,是Go1.18的新特性,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2022-04-04

最新評論