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

目录
  • 1. 执行命令并获得输出结果
  • 2. 将stdout和stderr分别处理
  • 3. 异步执行命令
  • 4. 执行时带上环境变量
  • 5. 预先检查命令是否存在
  • 6. 两个命令依次执行,管道通信
  • 7. 按行读取输出内容
  • 8. 获得exit code

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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 如何让shell终端和goland控制台输出彩色的文字

    终端输出彩色文字 开发工具:Mac,Goland,Mac自带shell.这是基于Mac的测试结果,根据读者留言,在Windows上不生效,标识符不一样. 在终端输出这段命令,将的到一个红色背景.绿色文字,并不停闪烁的输出. sszxr:~ sszxr$ echo -e "\033[5;32;41mI ♡ You \033[0m" I ♡ You sszxr:~ sszxr$ 双引号中的反斜杠\表示转义,033是标识符,表示用来设置颜色,[表示开始颜色设置,m为颜色设置结束.[后面的5表

  • linux中用shell快速安装配置Go语言的开发环境

    介绍 go1.5+版本提供编译好的安装包,我们只需要解压到相应的目录,并添加一些环境变量的配置即可. Go语言的安装步骤 下载安装包go1.7.linux-amd64.tar.gz 解压文件到指定目录: tar -zxf go1.7.linux-amd64.tar.gz 设置环境变量:GOROOT, GOPATH, PATH 既然我们可以列出这些步骤,那么便可以将整个过程自动化. 下面是安装脚本 #!/bin/bash #Upgrade go version to 1.7 #wget https

  • go调用shell命令两种方式实现(有无返回值)

    目录 阻塞方式(需要执行结果) 适用于执行普通非阻塞shell命令,且需要shell标准输出的 非阻塞方式(不需要执行结果) 阻塞方式(需要执行结果) 主要用于执行shell命令,并且返回shell的标准输出 适用于执行普通非阻塞shell命令,且需要shell标准输出的 //阻塞式的执行外部shell命令的函数,等待执行完毕并返回标准输出 func exec_shell(s string) (string, error){ //函数返回一个*Cmd,用于使用给出的参数执行name指定的程序 c

  • Go语言调用Shell与可执行文件的实现

    os/exec包可用于调用外部命令,可以使用管道连接输入输出,并支持阻塞与非阻塞方式执行命令. os/exec包中关键的类型为Cmd,以下介绍的所有方法皆服务于该类型: func Command(name string, arg ...string) *Cmd 方法返回一个*Cmd, 用于执行name指定的程序(携带arg参数) func (c *Cmd) Run() error 执行Cmd中包含的命令,阻塞直到命令执行完成 func (c *Cmd) Start() error 执行Cmd中包

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

    目录 1. 执行命令并获得输出结果 2. 将stdout和stderr分别处理 3. 异步执行命令 4. 执行时带上环境变量 5. 预先检查命令是否存在 6. 两个命令依次执行,管道通信 7. 按行读取输出内容 8. 获得exit code 1. 执行命令并获得输出结果 CombinedOutput() 执行程序返回 standard output and standard error func main() { cmd := exec.Command("ls", "-lah

  • 详解安装Ubuntu Linux系统时硬盘分区最合理的方法

    无论是安装Windows还是Linux操作系统,硬盘分区都是整个系统安装过程中最为棘手的环节,网上的一些Ubuntu Linux安装教程一般都是自动分区,给初学者带来很大的不便,下面我就根据多年来在装系统的经验谈谈安装Ubuntu Linux系统时硬盘分区最合理的方法. 在讲硬盘分区之前,我先来普及一下硬盘的相关分类,硬盘一般分为IDE硬盘.SCSI硬盘和SATA硬盘三种,在Linux系统中,IDE接口的硬盘被称为hd,SCSI和SATA接口的硬盘则被称为sd,其中IDE硬盘基本上已经淘汰,现在

  • Linux Shell获取文件夹下的文件名方法

    有时候需要获取某个文件夹下的所有文件名,可以用程序实现,但是打开IDE,编译运行太麻烦,在Linux服务器中通常不能打开IDE,此时可以用几行简单的shell命令来实现,结果保存到某个文件中即可. Shell脚本如下: #!/bin/bash # get all filename in specified path path=$1 files=$(ls $path) for filename in $files do echo $filename >> filename.txt done 以上

  • Python2.x利用commands模块执行Linux shell命令

    用Python写运维脚本时,经常需要执行linux shell的命令,Python中的commands模块专门用于调用Linux shell命令,并返回状态和结果,下面是commands模块的3个主要函数: 1. commands.getoutput('shell command') 执行shell命令,返回结果(string类型) 复制代码 代码如下: >>> commands.getoutput('pwd') '/home/oracle' 2. commands.getstatus(

  • Ruby中执行Linux shell命令的六种方法详解

    在Ruby中,执行shell命令是一件不奇怪的事情,Ruby提供了大概6种方法供开发者进行实现.这些方法都很简单,本文将具体介绍一下如何在Ruby脚本中进行调用终端命令. exec exec会将指定的命令替换掉当前进程中的操作,指定命令结束后,进程结束. 复制代码 代码如下: exec 'echo "hello world"' print 'abc' 执行上述的命令,结果如下,我们可以看到没有abc的输出,可以看出来,在执行echo "hello world"命令后

  • 在docker中执行linux shell命令的操作

    在docker中执行shell命令,需要在命令前增加sh -c,例如: docker run ubuntu sh -c 'cat /data/a.txt > b.txt' 否则,指令无法被正常解析. 补充:[Docker应用] docker中执行指定脚本(docker 下运行springboot应用) [Docker应用] docker中执行指定脚本 这里是执行spring boot的应用的实例: 1. 制作执行sh脚本的镜像文件(模板) Dockfile FROM vertigomedia/u

  • Linux shell命令帮助格式详解

    前言 linux shell命令通常可以通过-h或--help来打印帮助说明,或者通过man命令来查看帮助,有时候我们也会给自己的程序写简单的帮助说明,其实帮助说明格式是有规律可循的 帮助示例 下面是git reset命令的帮助说明,通过man git-reset可以查看 git reset [-q] [<tree-ish>] [--] <paths>... git reset (--patch | -p) [<tree-ish>] [--] [<paths>

  • linux shell命令行选项与参数用法详解

    问题描述:在linux shell中如何处理tail -n 10 access.log这样的命令行选项?在bash中,可以用以下三种方式来处理命令行参数,每种方式都有自己的应用场景.1,直接处理,依次对$1,$2,...,$n进行解析,分别手工处理:2,getopts来处理,单个字符选项的情况(如:-n 10 -f file.txt等选项):3,getopt,可以处理单个字符选项,也可以处理长选项long-option(如:--prefix=/home等).总结:小脚本手工处理即可,getopt

  • Go依赖注入DI工具wire使用详解(golang常用库包)

    目录 什么是依赖注入 第一次编写mysql操作类: 第二次编写mysql操作类: 第三次编写mysql操作类: 何时使用依赖注入 wire 概念说明 provider 和 injector provider injector wire 使用 快速开始 小结 绑定接口 Provider Set 参考 google 出品的依赖注入库 wire:https://github.com/google/wire 什么是依赖注入 依赖注入 ,英文全名是 dependency injection,简写为 DI.

  • 一文详解Golang 定时任务库 gron 设计和原理

    目录 cron 简介 gron 定时参数 源码解析 Cron Entry 按照时间排序 新增定时任务 启动和停止 Schedule 扩展性 经典写法-控制退出 结语 cron 简介 在 Unix-like 操作系统中,有一个大家都很熟悉的 cli 工具,它能够来处理定时任务,周期性任务,这就是: cron. 你只需要简单的语法控制就能实现任意[定时]的语义.用法上可以参考一下这个Crontab Guru Editor,做的非常精巧. 简单说,每一个位都代表了一个时间维度,* 代表全集,所以,上面

随机推荐