ZetCode

Go exec 命令

最后修改时间 2024 年 4 月 11 日

在本文中,我们将展示如何在 Golang 中执行 shell 命令和程序。

Run 函数启动指定的命令并等待其完成,而 Start 启动指定的命令但不等待其完成;我们需要将 WaitStart 一起使用。

Go os/exec

os/exec 包运行外部命令。它封装了 os.StartProcess,以便更轻松地重新映射 stdin 和 stdout,使用管道连接 I/O,以及进行其他调整。

Go exec 程序

Run 启动指定的命令并等待其完成。

runprg.go
package main

import (
    "log"
    "os/exec"
)

func main() {

    cmd := exec.Command("firefox")

    err := cmd.Run()

    if err != nil {
        log.Fatal(err)
    }
}

在代码示例中,我们执行 Firefox 浏览器。

Go exec.Command

Command 返回 Cmd 结构体,用于执行指定的程序及其参数。第一个参数是要运行的程序;其他参数是传递给程序的参数。

command.go
package main

import (
    "bytes"
    "fmt"
    "log"
    "os/exec"
    "strings"
)

func main() {
    cmd := exec.Command("tr", "a-z", "A-Z")

    cmd.Stdin = strings.NewReader("and old falcon")

    var out bytes.Buffer
    cmd.Stdout = &out

    err := cmd.Run()

    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("translated phrase: %q\n", out.String())
}

在代码示例中,我们通过 tr 命令转换输入。

cmd := exec.Command("tr", "a-z", "A-Z")

tr 是标准的 Linux 命令,用于转换、压缩和/或删除标准输入中的字符,并将结果写入标准输出。在我们的例子中,我们将小写字母转换为大写字母。

cmd.Stdin = strings.NewReader("and old falcon")

通过 Stdin 字段,我们将一个字符串作为输入传递给命令。

var out bytes.Buffer
cmd.Stdout = &out

程序的输出将写入字节缓冲区。

$ go run command.go
translated phrase: "AND OLD FALCON"

Go exec 命令带多个参数

我们可以向 exec.Command 传递多个参数。

multiple_args.go
package main

import (
    "fmt"
    "os/exec"
)

func main() {

    prg := "echo"

    arg1 := "there"
    arg2 := "are three"
    arg3 := "falcons"

    cmd := exec.Command(prg, arg1, arg2, arg3)
    stdout, err := cmd.Output()

    if err != nil {
        fmt.Println(err.Error())
        return
    }

    fmt.Print(string(stdout))
}

该示例运行带有三个参数的 echo 命令。

$ go run multiple_args.go
there are three falcons

Go exec 命令捕获输出

Output 运行命令并返回其标准输出。

capture_output.go
package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {

    out, err := exec.Command("ls", "-l").Output()

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(string(out))
}

该示例捕获 ls 命令的输出并打印它。

Go cmd.StdinPipe

管道允许我们将一个命令的输出发送到另一个命令。StdinPipe 返回一个管道,该管道将在命令启动时连接到命令的标准输入。

stdinpipe.go
package main

import (
    "fmt"
    "io"
    "log"
    "os/exec"
)

func main() {

    cmd := exec.Command("cat")
    stdin, err := cmd.StdinPipe()
    if err != nil {
        log.Fatal(err)
    }

    go func() {
        defer stdin.Close()
        io.WriteString(stdin, "an old falcon")
    }()

    out, err := cmd.CombinedOutput()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%s\n", out)
}

在代码示例中,我们在 goroutine 中将一个字符串写入标准输入。

cmd := exec.Command("cat")

cat 命令将给定的文件连接到标准输出。当不提供文件或使用 - 时,该命令从标准输入读取并将其打印到标准输出。

stdin, err := cmd.StdinPipe()

我们获取 cat 命令的标准输入管道。

go func() {
    defer stdin.Close()
    io.WriteString(stdin, "an old falcon")
}()

在 goroutine 中,我们将一个字符串写入 stdin 管道。

$ go run stdinpipe.go
an old falcon

Go cmd.StdoutPipe

StdoutPipe 返回一个管道,该管道将在命令启动时连接到命令的标准输出。

stdoutpipe.go
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os/exec"
    "strings"
)

func upper(data string) string {

    return strings.ToUpper(data)
}

func main() {
    cmd := exec.Command("echo", "an old falcon")

    stdout, err := cmd.StdoutPipe()

    if err != nil {
        log.Fatal(err)
    }

    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }

    data, err := ioutil.ReadAll(stdout)

    if err != nil {
        log.Fatal(err)
    }

    if err := cmd.Wait(); err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%s\n", upper(string(data)))
}

该示例通过管道读取 echo 命令的输出,并将其转换为大写字母。

cmd := exec.Command("echo", "an old falcon")

要运行的命令是带有单个字符串参数的 echo 命令。

stdout, err := cmd.StdoutPipe()

我们获取标准输出管道。

if err := cmd.Start(); err != nil {
    log.Fatal(err)
}

使用 Start 函数执行命令;它不会等待其完成。

data, err := ioutil.ReadAll(stdout)

我们从管道读取数据。

if err := cmd.Wait(); err != nil {
    log.Fatal(err)
}

Wait 等待命令退出,并等待 stdin 的所有复制或 stdout 或 stderr 的复制完成。它会在看到命令退出后关闭管道。

$ go run stdoutpipe.go
AN OLD FALCON

来源

Go os 包 - 参考

在本文中,我们执行了 Golang 中的外部命令。

作者

我的名字是 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。到目前为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Go 教程