詳解golang執(zhí)行Linux shell命令完整場景下的使用方法
1. 執(zhí)行命令并獲得輸出結(jié)果
CombinedOutput()
執(zhí)行程序返回 standard output and standard error
func main() {
cmd := exec.Command("ls", "-lah")
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
fmt.Printf("combined out:\n%s\n", string(out))
}
Output()
執(zhí)行程序返回standard output
func main() {
out, err := exec.Command("date").Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("The date is %s\n", out)
}
2. 將stdout和stderr分別處理
用buffer接受輸出
func main() {
cmd := exec.Command("ls", "-lah")
var stdin, stdout, stderr bytes.Buffer
cmd.Stdin = &stdin
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
fmt.Printf("out:\n%s\nerr:\n%s\n", outStr, errStr)
}
直接打印到屏幕
func main() {
cmd := exec.Command("ls", "-lah")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
err := cmd.Run()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
}
3. 異步執(zhí)行命令
cmd.Run() 阻塞等待命令執(zhí)行結(jié)束
cmd.Start() 不會等待命令完成
package main
import (
? ? "bytes"
? ? "fmt"
? ? "io"
? ? "log"
? ? "os"
? ? "os/exec"
)
func main() {
? ? var stdoutBuf, stderrBuf bytes.Buffer
? ? cmd := exec.Command("bash", "-c", "for i in 1 2 3 4;do echo $i;sleep 2;done")
? ? stdoutIn, _ := cmd.StdoutPipe()
? ? stderrIn, _ := cmd.StderrPipe()
? ? var errStdout, errStderr error
? ? stdout := io.MultiWriter(os.Stdout, &stdoutBuf)
? ? stderr := io.MultiWriter(os.Stderr, &stderrBuf)
? ? err := cmd.Start()
? ? if err != nil {
? ? ? ? log.Fatalf("cmd.Start() failed with '%s'\n", err)
? ? }
? ? go func() {
? ? ? ? _, errStdout = io.Copy(stdout, stdoutIn)
? ? }()
? ? go func() {
? ? ? ? _, errStderr = io.Copy(stderr, stderrIn)
? ? }()
? ? err = cmd.Wait()
? ? if err != nil {
? ? ? ? log.Fatalf("cmd.Run() failed with %s\n", err)
? ? }
? ? if errStdout != nil || errStderr != nil {
? ? ? ? log.Fatal("failed to capture stdout or stderr\n")
? ? }
? ? outStr, errStr := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())
? ? fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
}4. 執(zhí)行時帶上環(huán)境變量
func main() {
cmd := exec.Command("bash", "-c", "programToExecute")
additionalEnv := "programToExecute=ls"
newEnv := append(os.Environ(), additionalEnv)
cmd.Env = newEnv
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
fmt.Printf("%s", out)
}
5. 預(yù)先檢查命令是否存在
func checkLsExists() {
path, err := exec.LookPath("ls")
if err != nil {
fmt.Printf("didn't find 'ls' executable\n")
} else {
fmt.Printf("'ls' executable is in '%s'\n", path)
}
}
6. 兩個命令依次執(zhí)行,管道通信
func main() {
c1 := exec.Command("ls")
c2 := exec.Command("wc", "-l")
r, w := io.Pipe()
c1.Stdout = w
c2.Stdin = r
var b2 bytes.Buffer
c2.Stdout = &b2
c1.Start()
c2.Start()
c1.Wait()
w.Close()
c2.Wait()
io.Copy(os.Stdout, &b2)
}
或者
func main() {
c1 := exec.Command("ls")
c2 := exec.Command("wc", "-l")
c2.Stdin, _ = c1.StdoutPipe()
c2.Stdout = os.Stdout
_ = c2.Start()
_ = c1.Run()
_ = c2.Wait()
}
反正下面這樣是不行的
func main() {
c := exec.Command("ls", "|", "wc", "-l")
c.Stdout = os.Stdout
_ = c.Run()
}
不嫌丑可以用bash -c
func main() {
cmd := "cat /proc/cpuinfo | egrep '^model name' | uniq | awk '{print substr($0, index($0,$4))}'"
out, err := exec.Command("bash", "-c", cmd).Output()
if err != nil {
fmt.Printf("Failed to execute command: %s", cmd)
}
fmt.Println(string(out))
}
7. 按行讀取輸出內(nèi)容
func main() {
cmd := exec.Command("ls", "-la")
stdout, _ := cmd.StdoutPipe()
cmd.Start()
reader := bufio.NewReader(stdout)
for {
line, err := reader.ReadString('\n')
line = strings.TrimSpace(line)
if err != nil || io.EOF == err {
break
}
log.Println(line)
}
cmd.Wait()
}
8. 獲得exit code
func RunCommand(name string, args ...string) (stdout string, stderr string, exitCode int) {
? ? log.Println("run command:", name, args)
? ? var outbuf, errbuf bytes.Buffer
? ? cmd := exec.Command(name, args...)
? ? cmd.Stdout = &outbuf
? ? cmd.Stderr = &errbuf
? ? err := cmd.Run()
? ? stdout = outbuf.String()
? ? stderr = errbuf.String()
? ? if err != nil {
? ? ? ? // try to get the exit code
? ? ? ? if exitError, ok := err.(*exec.ExitError); ok {
? ? ? ? ? ? ws := exitError.Sys().(syscall.WaitStatus)
? ? ? ? ? ? exitCode = ws.ExitStatus()
? ? ? ? } else {
? ? ? ? ? ? // This will happen (in OSX) if `name` is not available in $PATH,
? ? ? ? ? ? // in this situation, exit code could not be get, and stderr will be
? ? ? ? ? ? // empty string very likely, so we use the default fail code, and format err
? ? ? ? ? ? // to string and set to stderr
? ? ? ? ? ? log.Printf("Could not get exit code for failed program: %v, %v", name, args)
? ? ? ? ? ? exitCode = defaultFailedCode
? ? ? ? ? ? if stderr == "" {
? ? ? ? ? ? ? ? stderr = err.Error()
? ? ? ? ? ? }
? ? ? ? }
? ? } else {
? ? ? ? // success, exitCode should be 0 if go is ok
? ? ? ? ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
? ? ? ? exitCode = ws.ExitStatus()
? ? }
? ? log.Printf("command result, stdout: %v, stderr: %v, exitCode: %v", stdout, stderr, exitCode)
? ? return
}參考鏈接:
https://saucer-man.com/backend_development/571.html
到此這篇關(guān)于詳解golang執(zhí)行Linux shell命令完整場景下的使用方法的文章就介紹到這了,更多相關(guān)golang執(zhí)行Linux shell內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GO 使用Webhook 實現(xiàn)github 自動化部署的方法
這篇文章主要介紹了GO 使用Webhook 實現(xiàn)github 自動化部署的方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05
golang進(jìn)程在docker中OOM后hang住問題解析
這篇文章主要介紹了golang進(jìn)程在docker中OOM后hang住問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
詳解Golang net/http包中的RoundTripper接口
RoundTripper 是 net/http 包中的一個接口,定義了處理 HTTP 請求返回和響應(yīng)的方法,是 http.Client 結(jié)構(gòu)體中執(zhí)行 http 請求的核心部分,本文將詳細(xì)的給大家介紹Golang RoundTripper接口,需要的朋友可以參考下2023-09-09

