有时候我们的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))
}
运行结果:
➜ go run spawning-processes.go
> date
2025年 1月21日 星期二 09时42分07秒 CST
command exit rc = 1
> grep hello
hello grep
> ls -a -l -h
total 8
drwxr-xr-x 3 lazy staff 96B 1 21 09:41 .
drwxr-xr-x 47 lazy staff 1.5K 1 21 09:41 ..
-rw-r--r-- 1 lazy staff 2.3K 1 21 09:41 spawning-processes.go
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。