• golang执行Linux shell命令完整场景下的使用方法


    1. 执行命令并获得输出结果

    • CombinedOutput()

    执行程序返回 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))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • Output()

    执行程序返回standard output

    func main() {
        out, err := exec.Command("date").Output()
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("The date is %s\n", out)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 直接打印到屏幕

      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)
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    3. 异步执行命令

    cmd.Run() 阻塞等待命令执行结束
    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)
    }
    
    • 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

    4. 执行时带上环境变量

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5. 预先检查命令是否存在

    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)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6. 两个命令依次执行,管道通信

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    或者

    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()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    反正下面这样是不行的

    func main() {
        c := exec.Command("ls", "|", "wc", "-l")
        c.Stdout = os.Stdout
        _ = c.Run()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    不嫌丑可以用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))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    7. 按行读取输出内容

    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()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

    参考链接:

    https://saucer-man.com/backend_development/571.html

  • 相关阅读:
    猿创征文|C#基础——DBHelper
    阿米巴经营管理模式是什么,能做什么,有什么好处和坏处?
    ROS1和ROS2的区别
    器学习算法(六)基于天气数据集的XGBoost分类预测
    Lesson 1 A private conversation
    QGIS创建要素与属性
    latex线上编译器以及三线表代码
    Vite - 配置 - 不同的环境执行不同的配置文件
    Python动态建模(2)
    [附源码]java毕业设计海雨市高校实验设备报修系统
  • 原文地址:https://blog.csdn.net/a772304419/article/details/125525985