有时我们的 Go 程序需要生成其他非 Go 进程。
|
|
|
package main
|
|
import (
"fmt"
"io"
"os/exec"
)
|
|
func main() {
|
我们将从一个简单的命令开始,该命令不接受任何参数或输入,只向标准输出打印一些内容。exec.Command 帮助程序创建一个对象来表示此外部进程。
|
dateCmd := exec.Command("date")
|
Output 方法运行命令,等待其完成并收集其标准输出。如果没有错误,dateOut 将保存包含日期信息的字节。
|
dateOut, err := dateCmd.Output()
if err != nil {
panic(err)
}
fmt.Println("> date")
fmt.Println(string(dateOut))
|
Output 和 Command 的其他方法将在执行命令时出现问题(例如,路径错误)时返回 *exec.Error ,如果命令运行但退出时返回非零返回值,则返回 *exec.ExitError 。
|
_, err = exec.Command("date", "-x").Output()
if err != nil {
switch e := err.(type) {
case *exec.Error:
fmt.Println("failed executing:", err)
case *exec.ExitError:
fmt.Println("command exit rc =", e.ExitCode())
default:
panic(err)
}
}
|
接下来,我们将研究一个稍微复杂的情况,我们向外部进程的 stdin 管道数据,并从其 stdout 收集结果。
|
grepCmd := exec.Command("grep", "hello")
|
在这里,我们显式地获取输入/输出管道,启动进程,向其写入一些输入,读取生成的输出,最后等待进程退出。
|
grepIn, _ := grepCmd.StdinPipe()
grepOut, _ := grepCmd.StdoutPipe()
grepCmd.Start()
grepIn.Write([]byte("hello grep\ngoodbye grep"))
grepIn.Close()
grepBytes, _ := io.ReadAll(grepOut)
grepCmd.Wait()
|
我们在上面的示例中省略了错误检查,但您可以对所有错误使用通常的 if err != nil 模式。我们也只收集了 StdoutPipe 结果,但您可以以完全相同的方式收集 StderrPipe 。
|
fmt.Println("> grep hello")
fmt.Println(string(grepBytes))
|
请注意,在生成命令时,我们需要提供一个明确划分的命令和参数数组,而不是能够只传入一个命令行字符串。如果您想使用字符串生成完整的命令,可以使用 bash 的 -c 选项
|
lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
lsOut, err := lsCmd.Output()
if err != nil {
panic(err)
}
fmt.Println("> ls -a -l -h")
fmt.Println(string(lsOut))
}
|