go执行外部命令
# 执行外部命令
# 1. 方式一:run
code
func main() { cmd := exec.Command("ls", "-l", "/var/log/") err := cmd.Run() if err != nil { log.Fatalf("cmd.Run() failed with %s\n", err) } }
1
2
3
4
5
6
7Run()
方法会启动命令并等待命令执行完毕。它会阻塞当前 goroutine 直到命令执行完毕,并返回一个error
对象,该对象表示命令执行的错误信息。如果命令执行成功,Run()
方法会返回nil
- 直接调用 Cmd 对象的 Run 函数,返回的只有成功和失败,获取不到任何输出的结果
# 2. 方式二:start & wait
code
func main() { // 使用 Start() 方法启动命令 cmd = exec.Command("ping", "www.baidu.com") if err := cmd.Start(); err != nil { fmt.Println("Error:", err) } if err := cmd.Wait(); err != nil { fmt.Println("Error:", err) } }
1
2
3
4
5
6
7
8
9
10Start()
方法会启动命令并立即返回。它不会等待命令执行完毕,而是会在后台异步执行命令。Start()
方法返回一个error
对象,该对象表示启动命令的错误信息。如果命令启动成功,Start()
方法会返回nil
在使用
Start()
方法启动命令后,我们可以使用Wait()
方法等待命令执行完毕。Wait()
方法会阻塞当前 goroutine 直到命令执行完毕,并返回一个error
对象,该对象表示命令执行的错误信息。如果命令执行成功,Wait()
方法会返回nil
# 输出日志
https://darjun.github.io/2022/11/01/godailylib/osexec/
# 1. 标准输出
code
func main() { cmd := exec.Command("cal") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { log.Fatalf("cmd.Run() failed: %v\n", err) } }
1
2
3
4
5
6
7
8
9
# 2. 转存文件
code
func main() { f, err := os.OpenFile("out.txt", os.O_WRONLY|os.O_CREATE, os.ModePerm) if err != nil { log.Fatalf("os.OpenFile() failed: %v\n", err) } cmd := exec.Command("cal") cmd.Stdout = f cmd.Stderr = f err = cmd.Run() if err != nil { log.Fatalf("cmd.Run() failed: %v\n", err) } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3. 发送到网络
code
func cal(w http.ResponseWriter, r *http.Request) { year := r.URL.Query().Get("year") month := r.URL.Query().Get("month") cmd := exec.Command("cal", month, year) cmd.Stdout = w cmd.Stderr = w err := cmd.Run() if err != nil { log.Fatalf("cmd.Run() failed: %v\n", err) } } func main() { http.HandleFunc("/cal", cal) http.ListenAndServe(":8080", nil) }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 4. 手动捕获
code
package middleware import ( "bufio" "fmt" "git-biz.qianxin-inc.cn/upming/component/sdk-go-framework.git/log" "io" "os/exec" ) type stdType int32 const ( stdTypeStdout stdType = iota + 1 stdTypeStderr ) func forkStdLog(cmd *exec.Cmd) error { // 捕获标准输出 stdout, err := cmd.StdoutPipe() if err != nil { return fmt.Errorf("cmd.StdoutPipe() failed with %v", err) } go func() { printExecStd(bufio.NewReader(stdout)) }() // 捕获标准错误 stderr, err := cmd.StderrPipe() if err != nil { return fmt.Errorf("cmd.StderrPipe() failed with %v", err) } go func() { // printExecStd(bufio.NewReader(stderr), stdTypeStderr) // TODO 中间件s的输出不标准,后期再处理,需要加上这个参数 printExecStd(bufio.NewReader(stderr)) }() return nil } func printExecStd(reader *bufio.Reader, std ...stdType) { logger := log.WithField("[ middleware_s ]", "printExecStd") var s stdType if len(std) > 0 { s = std[0] } else { s = stdTypeStdout } outputBytes := make([]byte, 1024) for { n, err := reader.Read(outputBytes) // 获取屏幕的实时输出(并不是按照回车分割) if err != nil { if err == io.EOF { break } logger.Errorf("read %s failed with %v", std, err) } output := string(outputBytes[:n]) if s == stdTypeStdout { logger.Info(output) } else if s == stdTypeStderr { logger.Error(output) } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
上次更新: 2023/08/27, 21:33:49