您现在的位置是:首页 > 编程 > 

Go每日一库之197:os/exec(调用外部程序)

2025-07-27 15:16:04
Go每日一库之197:os/exec(调用外部程序) 有时候我们需要通过代码的方式去执行 linux 命令,那么 os/exec 这个系统库刚好提供了相应的功能。Golang语言中提供了一个 os/exec 包,它提供了一组函数和结构,用于调用外部程序,这些外部程序可以是系统自带的,也可以是用户自定义的。os/exec 包中提供了一组函数,用于执行系统命令,我们可以使用它来执行系统的cmd命令行。

Go每日一库之197:os/exec(调用外部程序)

有时候我们需要通过代码的方式去执行 linux 命令,那么 os/exec 这个系统库刚好提供了相应的功能。

Golang语言中提供了一个 os/exec 包,它提供了一组函数和结构,用于调用外部程序,这些外部程序可以是系统

自带的,也可以是用户自定义的。os/exec 包中提供了一组函数,用于执行系统命令,我们可以使用它来执行系

统的cmd命令行。

exec包执行外部命令,它将 os.StartProcess 进行包装使得它更容易映射到 stdin 和 stdout,并且利用 pipe 连接i/o。

参考文档:/os/exec

Command方法代码语言:javascript代码运行次数:0运行复制
func Command(name string, arg ...string) *Cmd {}

使用 exec.Command 函数来创建一个 Cmd 结构体,该函数接受两个参数,第一个参数是要执行的命令,第二个

参数是命令行参数,比如 ls -l,那么第一个参数就是 ls,第二个参数就是 -l。

Run方法代码语言:javascript代码运行次数:0运行复制
func (c *Cmd) Run() error {}

使用 Run 函数来执行这个命令,Run 函数会根据我们传入的参数来执行命令,并返回一个 error 类型的结果。

  • 分开读取 Stdout 和 Stderr
代码语言:javascript代码运行次数:0运行复制
func main() {
    var outbuf, errbuf bytes.Buffer

    cmd := exec.Command("bash", "test.sh")
    cmd.Stdout = &outbuf
    cmd.Stderr = &errbuf

    var err error = cmd.Run();
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Stdout: [%s]\n", string(outbuf.Bytes()))
    fmt.Printf("Stderr: [%s]\n", string(errbuf.Bytes()))
}
进程退出状态码ExitCode 代码语言:javascript代码运行次数:0运行复制
func main() {

    cmd := exec.Command("bash", "test.sh")
    var err error = cmd.Run();
    if err != nil {
        log.Fatal(err)
    }
    
	// 获取命令的退出状态码
	exitCode := cmd.ProcessState.ExitCode()
	fmt.Println("ExitCode:", exitCode)
}
查cmd命令的可执行二进制文件代码语言:javascript代码运行次数:0运行复制
func main() {
    f, err := exec.LookPath("ls")
    if err != nil {
        fmt.Println(err)
    }
    // /usr/bin/ls
    fmt.Println(f)
}
对标准输入执行cmd命令代码语言:javascript代码运行次数:0运行复制
func main() { 
    // 进行字符串的替换
    cmd := exec.Command("tr", "a-z", "A-Z")
    cmd.Stdin = ("some input") 
    var out bytes.Buffer 
    cmd.Stdout = &out 
    err := cmd.Run() 
    if err != nil { 
        log.Fatal(err) 
    } 
    // in all caps: SOME IPUT
    fmt.Printf("in all caps: %s\n", out.String())
}
标准输出Output和CombinedOutput代码语言:javascript代码运行次数:0运行复制
//运行命令并返回其标准输出
func (c *Cmd) Output() ([]byte, error)

// 运行命令,并返回标准输出和标准错误
func (c *Cmd) CombinedOutput() ([]byte, error)

注意:Output() 和 CombinedOutput() 不能够同时使用,因为 command 的标准输出只能有一个,同时使用的话,便会报错。

  • Output 仅返回标准输出
代码语言:javascript代码运行次数:0运行复制
func main() {
    cmd := exec.Command("bash", "test.sh")
    out, err := cmd.Output()
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("stdout=[%s]\n", string(out))
}
  • CombinedOutput 将标准输出和标准错误合并返回
代码语言:javascript代码运行次数:0运行复制
func main() {
    cmd := exec.Command("ls", "-l", "/opt/software/")
    out, err := cmd.CombinedOutput()
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(out)) 
}
执行命令 Run和 Start代码语言:javascript代码运行次数:0运行复制
// 开始指定命令并且等待它执行结束,如果命令能够成功执行完毕,则返回nil,否则的话边会产生错误
func (c *Cmd) Run() error

// 使某个命令开始执行,但是并不等到他执行结束,这点和Run命令有区别,然后使用Wait方法等待命令执行完毕并且释放响应的资源        
func (c *Cmd) Start() error   

注:一个 command 只能使用 Start() 或者 Run() 中的一个启动命令,不能两个同时使用。

Start 执行不会等待命令完成,Run会阻塞等待命令完成。

下面看一下两个命令的区别:

  • Run 直接运行并获取结果
代码语言:javascript代码运行次数:0运行复制
func main() {
    log.Println("start")
    cmd := exec.Command("sleep", "10")
    // 执行到此处时会阻塞等待10秒
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
    log.Println("end")
}
  • Start 要和 Wait 一起使用:
代码语言:javascript代码运行次数:0运行复制
func main() {
    log.Println("start")
    cmd := exec.Command("sleep", "10")
    // 如果用start则直接向后运行
    err := cmd.Start()
    if err != nil {
        log.Fatal(err)
    }
    log.Println("end")
    // 执行Start会在此处等待10秒
    err = cmd.Wait()
    if err != nil {
        log.Fatal(err)
    }
    log.Println("wait")
}
管道Pipe代码语言:javascript代码运行次数:0运行复制
// StderrPipe返回一个pipe,这个管道连接到command的标准错误,当command命令退出时,wait将关闭这些pipe
func (c *Cmd) StderrPipe() (io.ReadCloser, error)

// StdinPipe返回一个连接到command标准输入的管道pipe
func (c *Cmd) StdinPipe() (io.WriteCloser, error)

// StdoutPipe返回一个连接到command标准输出的管道pipe
func (c *Cmd) StdoutPipe() (io.ReadCloser, error)
代码语言:javascript代码运行次数:0运行复制
package main
import (
    "fmt"
    "os"
    "os/exec"
)
func main() {
    cmd := exec.Command("cat")
    stdin, err := cmd.StdinPipe()
    if err != nil {
        fmt.Println(err)
    }
    _, err = stdin.Write([]byte(""))
    if err != nil {
        fmt.Println(err)
    }
    stdin.Close()
    // 终端标准输出
    cmd.Stdout = os.Stdout
}
代码语言:javascript代码运行次数:0运行复制
package main
import (
    "io/ioutil"
    "log"
    "os/exec"
)
func main() {
    cmd := exec.Command("ls", "-l", "/opt/software/")
    // 获取输出对象,可以从该对象中读取输出结果
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }
    // 保证关闭输出流
    defer stdout.Close()
    // 运行命令
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }
    // 读取输出结果
    if opBytes, err := ioutil.ReadAll(stdout); err != nil {
        log.Fatal(err)
    } else {
        log.Println(string(opBytes))
    }
    if err := cmd.Wait(); err != nil {
        log.Fatal(err)
    }
}
将命令的输出结果重定向到文件中代码语言:javascript代码运行次数:0运行复制
package main
import (
    "log"
    "os"
    "os/exec"
)
func main() {
    cmd := exec.Command("ls", "-l", "/opt/software/")
    stdout, err := os.OpenFile("stdout.log", os.O_CREATE|os.O_WROLY, 0600)
    if err != nil {
        log.Fatalln(err)
    }
    defer stdout.Close()
    // 重定向标准输出到文件
    cmd.Stdout = stdout
    // 执行命令
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }
    if err := cmd.Wait(); err != nil {
        log.Fatal(err)
    }
}
执行过程中想要杀死cmd的执行代码语言:javascript代码运行次数:0运行复制
func main() {
    log.Println("start")
    CanKillRun()
    log.Println("end")
}
// 执行完发挥的数据结构
type result struct {
    err    error
    output []byte
}
// 能够杀死的进程
func CanKillRun() {
    var (
        cmd        *exec.Cmd
        ctx        context.Context
        cancelFunc context.CancelFunc
        resultChan chan *result
        res        *result
    )
    // 创建一个通道用户协程交换数据
    resultChan = make(chan *result, 1000)
    // 拿到这个上下文的取消方法
    ctx, cancelFunc = context.WithCancel(context.TODO())
    // 起一个goroutine可以理解是子进程去处理
    go func() {
        var (
            output []byte
            err    error
        )
        cmd = exec.CommandContext(ctx, "bash", "-c", "sleep ;echo hello;")
        // 执行任务,捕捉输出
        output, err = cmd.CombinedOutput()
        // 把任务执行结果输出给main协程
        resultChan <- &result{
            err:    err,
            output: output,
        }
    }()
    // 1s后我们就把他杀死
    // 继续往下走
    time.Sleep(1 * time.Second)
    // 取消上下文
    cancelFunc()
    // 读取通道里面的数据
    res = <-resultChan
    // 打印结果
    fmt.Println("err: ", , " out: ", string())
}
执行脚本并获取结果代码语言:javascript代码运行次数:0运行复制
/*
test.sh脚本内容
#!/bin/bash
for k in $( seq 1 10 )
do
   echo "Hello World $k"
   sleep 1
done
*/
var contentArray = make([]string, 0, 5)
func main() {
    command := "/bin/bash"
    params := []string{"-c", "sh test.sh"}
    execCommand(command, params)
}
func execCommand(commandame string, params []string) bool {
    contentArray = contentArray[0:0]
    cmd := exec.Command(commandame, params...)
    // 显示运行的命令
    fmt.Printf("执行命令: %s\n", strings.Join(cmd.Args, " "))
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        fmt.Fprintln(os.Stderr, "error=>", err.Error())
        return false
    }
    // Start开始执行包含的命令,但并不会等待该命令完成即返回
    // wait方法会返回命令的返回状态码并在命令返回后释放相关的资源
    cmd.Start()
    reader := (stdout)
    var index int
    // 实时循环读取输出流中的一行内容
    for {
        line, err2 := reader.ReadString('\n')
        if err2 != nil || io.EOF == err2 {
            break
        }
        fmt.Println(line)
        index++
        contentArray = append(contentArray, line)
    }
    cmd.Wait()
    return true
}

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1191733.html

相关标签:无
上传时间: 2025-07-22 23:16:41
留言与评论(共有 7 条评论)
本站网友 最新个人所得税计算器
19分钟前 发表
= "/bin/bash" params
本站网友 tpp是什么
25分钟前 发表
" out
本站网友 360小说网
5分钟前 发表
参考文档:/os/execCommand方法代码语言:javascript代码运行次数:0运行复制func Command(name string
本站网友 飞利浦剃须刀
13分钟前 发表
该函数接受两个参数
本站网友 三五九旅
4分钟前 发表
便会报错
本站网友 中小企业贷款
9分钟前 发表
= cmd.Start(); err != nil { log.Fatal(err) } if err