os/execlsmkdirgrepstdinstdout如果只是想看代码,可以在 Github 上查看
Exec我们可以使用官方的 os/exec 包来运行外部命令。
当我们执行 shell 命令时,我们是在 Go 应用程序之外运行代码。为此,我们需要在子进程中运行这些命令。
StdinStdout运行基本的 Shell 命令
*exec.Cmdls// 创建了一个新的 *Cmd 实例
// 使用 "ls" 命令和 "./" 参数作为参数
cmd := exec.Command("ls", "./")
// 使用 `Output` 方法执行该命令并收集其输出
out, err := cmd.Output()
if err != nil {
// 如果执行命令时出现错误,则输出错误信息
fmt.Println("could not run command: ", err)
}
// 否则,输出运行该命令的输出结果
fmt.Println("Output: ", string(out))
由于我在示例仓库中运行此代码,因此它会打印项目根目录中的文件:
> go run shellcommands/main.go
Output: LICENSE
README.md
go.mod
shellcommands
exec执行持久运行的命令
lsping➜ ~ ping google.com
PING google.com (142.250.77.110): 56 data bytes
64 bytes from 142.250.77.110: icmp_seq=0 ttl=116 time=11.397 ms
64 bytes from 142.250.77.110: icmp_seq=1 ttl=116 time=17.646 ms ## this is received after 1 second
64 bytes from 142.250.77.110: icmp_seq=2 ttl=116 time=10.036 ms ## this is received after 2 seconds
64 bytes from 142.250.77.110: icmp_seq=3 ttl=116 time=9.656 ms ## and so on
# ...
cmd.OutputOutputpingStdoutcmd := exec.Command("ping", "google.com")
// pipe the commands output to the applications
// standard output
cmd.Stdout = os.Stdout
// Run still runs the command and waits for completion
// but the output is instantly piped to Stdout
if err := cmd.Run(); err != nil {
fmt.Println("could not run command: ", err)
}
execpingos.Stdoutcmdcmd.Stdoutos.Stdoutcmd.Run()输出结果:
> go run shellcommands/main.go
PING google.com (142.250.195.142): 56 data bytes
64 bytes from 142.250.195.142: icmp_seq=0 ttl=114 time=9.397 ms
64 bytes from 142.250.195.142: icmp_seq=1 ttl=114 time=37.398 ms
64 bytes from 142.250.195.142: icmp_seq=2 ttl=114 time=34.050 ms
64 bytes from 142.250.195.142: icmp_seq=3 ttl=114 time=33.272 ms
# ...
# and so on
Stdout自定义输出写入程序
os.Stdoutio.Writer"received output:"type customOutput struct{}
func (c customOutput) Write(p []byte) (int, error) {
fmt.Println("received output: ", string(p))
return len(p), nil
}
customWritercmd.Stdout = customOutput{}如果我们现在运行应用程序,我们将得到以下输出:
received output: PING google.com (142.250.195.142): 56 data bytes
64 bytes from 142.250.195.142: icmp_seq=0 ttl=114 time=187.825 ms
received output: 64 bytes from 142.250.195.142: icmp_seq=1 ttl=114 time=19.489 ms
received output: 64 bytes from 142.250.195.142: icmp_seq=2 ttl=114 time=117.676 ms
received output: 64 bytes from 142.250.195.142: icmp_seq=3 ttl=114 time=57.780 ms
STDINSTDIN译注:就是外部给命令,然后去执行
grep➜ ~ echo "1. pear\n2. grapes\n3. apple\n4. banana\n" | grep apple
3. appleSTDINgrepgrep" apple"Cmdgrepcmd := exec.Command("grep", "apple")
// Create a new pipe, which gives us a reader/writer pair
reader, writer := io.Pipe()
// assign the reader to Stdin for the command
cmd.Stdin = reader
// the output is printed to the console
cmd.Stdout = os.Stdout
go func() {
defer writer.Close()
// the writer is connected to the reader via the pipe
// so all data written here is passed on to the commands
// standard input
writer.Write([]byte("1. pear\n"))
writer.Write([]byte("2. grapes\n"))
writer.Write([]byte("3. apple\n"))
writer.Write([]byte("4. banana\n"))
}()
if err := cmd.Run(); err != nil {
fmt.Println("could not run command: ", err)
}
输出:
3. appleKill 一个子进程
有几个命令会无限期地运行,或者需要明确的信号才能停止。
python3 -m http.serversleep 10000要停止这些进程,我们需要从应用程序发送终止信号。我们可以通过向命令添加一个上下文实例来做到这一点。
如果上下文被取消,命令也会终止。
ctx := context.Background()
// The context now times out after 1 second
// alternately, we can call `cancel()` to terminate immediately
ctx, cancel = context.WithTimeout(ctx, 1*time.Second)
cmd := exec.CommandContext(ctx, "sleep", "100")
out, err := cmd.Output()
if err != nil {
fmt.Println("could not run command: ", err)
}
fmt.Println("Output: ", string(out))
这将在 1 秒后给出以下输出:
could not run command: signal: killed
Output: 当您想要限制运行命令所花费的时间或想要创建回退以防命令未按时返回结果时,终止子进程很有用。
总结
os/execcmd.Outputcmd.Runcmd.Stdoutcmd.Stdin您可以在 Github 上查看所有示例的工作代码。