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

 更新时间:2022年06月30日 10:30:52   作者:学亮编程手记  
本文主要介绍了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))
}

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

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. 异步执行命令

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

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

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

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

或者

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. 按行读取输出内容

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

到此这篇关于详解golang执行Linux shell命令完整场景下的使用方法的文章就介绍到这了,更多相关golang执行Linux shell内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • GO 使用Webhook 实现github 自动化部署的方法

    GO 使用Webhook 实现github 自动化部署的方法

    这篇文章主要介绍了GO 使用Webhook 实现github 自动化部署的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • golang类型转换组件Cast的使用详解

    golang类型转换组件Cast的使用详解

    这篇文章主要介绍了golang类型转换组件Cast的使用详解,帮助大家更好的理解和学习使用golang,感兴趣的朋友可以了解下
    2021-02-02
  • 解决Golang json序列化字符串时多了\的情况

    解决Golang json序列化字符串时多了\的情况

    这篇文章主要介绍了解决Golang json序列化字符串时多了\的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • golang进程在docker中OOM后hang住问题解析

    golang进程在docker中OOM后hang住问题解析

    这篇文章主要介绍了golang进程在docker中OOM后hang住问题解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • golang连接kafka消费进ES操作

    golang连接kafka消费进ES操作

    这篇文章主要介绍了golang连接kafka消费进ES操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 详解Golang net/http包中的RoundTripper接口

    详解Golang net/http包中的RoundTripper接口

    RoundTripper 是 net/http 包中的一个接口,定义了处理 HTTP 请求返回和响应的方法,是 http.Client 结构体中执行 http 请求的核心部分,本文将详细的给大家介绍Golang RoundTripper接口,需要的朋友可以参考下
    2023-09-09
  • golang拼接字符串的5种实现方式

    golang拼接字符串的5种实现方式

    文章总结了五种拼接字符串的方式,包括使用 "+"、strings.Join()、fmt.Sprint、bytes.Buffer 和 strings.Builder,每种方式都有其适用场景和性能特点
    2024-12-12
  • Go 中的空白标识符下划线

    Go 中的空白标识符下划线

    这篇文章主要介绍了Go 中的空白标识符下划线,空白标识符是未使用的值的占位符,由下划线(_)表示,下文对其相关介绍需要的小伙伴可以参考一下
    2022-03-03
  • golang高并发的深入理解

    golang高并发的深入理解

    golang从语言级别上对并发提供了支持,而且在启动并发的方式上直接添加了语言级的关键字。下面这篇文章主要给大家介绍了关于golang高并发的相关资料,需要的朋友可以参考下
    2019-03-03
  • golang中实现graphql请求的方法

    golang中实现graphql请求的方法

    这篇文章主要介绍了如何在golang中实现graphql请求,在本文中,我们介绍了如何使用gqlgen来构建GraphQL服务,需要的朋友可以参考下
    2023-04-04

最新评论