在Golang中执行Shell命令的教程详解
作者:宇宙之一粟 发布时间:2024-04-25 15:10:51
Exec 包
我们可以使用官方的 os/exec 包来运行外部命令。
当我们执行 shell 命令时,我们是在 Go 应用程序之外运行代码。为此,我们需要在子进程中运行这些命令。
每个命令都作为正在运行的 Go 应用程序中的子进程运行,并公开我们可以用来从进程读取和写入数据的 Stdin 和 Stdout 属性。
运行基本的 Shell 命令
要运行一个简单的命令并读取其输出,我们可以创建一个新的 *exec.Cmd 实例并运行它。在此示例中,让我们使用 ls 列出当前目录中的文件,并打印代码的输出:
// 创建了一个新的 *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
时,我们的应用程序不会生成 shell,而是直接运行给定的命令。这意味着将不会执行任何基于 shell 的处理,例如 glob 模式或扩展。
执行持久运行的命令
前面的示例执行了 ls
命令,该命令立即返回了它的输出。那些输出是连续的,或者需要很长时间才能检索的命令呢?
例如,当我们运行 ping
命令时,我们会定期获得连续输出:
➜ ~ 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.Output
执行此类型的命令,我们将不会得到任何输出,因为 Output
方法等待命令执行,而 ping
命令执行时间无限。
相反,我们可以使用自定义的 Stdout
属性来连续读取输出:
cmd := 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)
}
这段代码使用 Go 语言的 exec 包来执行 ping 命令并将输出重定向到标准输出流(os.Stdout)。具体来说,它创建了一个命令对象(cmd),该对象包含要执行的命令(“ping"和"google.com”)。然后将命令的标准输出流(cmd.Stdout)设置为应用程序的标准输出流(os.Stdout)。最后,使用 cmd.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.Stdout
不同,我们可以创建实现 io.Writer
接口的自己的编写器。
让我们创建一个编写器,在每个输出块之前添加一个 "received output:"
前缀:
type customOutput struct{}
func (c customOutput) Write(p []byte) (int, error) {
fmt.Println("received output: ", string(p))
return len(p), nil
}
现在我们可以指定一个新的 customWriter
实例作为输出写入器:
cmd.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
使用 STDIN 将输入传递给命令
在前面的示例中,我们在不提供任何输入(或提供有限的输入作为参数)的情况下执行命令。在大多数情况下,输入是通过 STDIN
流给出的。
译注:就是外部给命令,然后去执行
一个著名的例子是 grep
命令,我们可以通过管道从另一个命令输入:
➜ ~ echo "1. pear\n2. grapes\n3. apple\n4. banana\n" | grep apple
3. apple
在这里,输入通过 STDIN
传递给 grep
命令。在本例中,输入是一个水果列表,grep
过滤包含 " apple"
的行。
Cmd
实例为我们提供了一个可以写入的输入流。让我们使用它向 grep
子进程传递输入:
cmd := 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. apple
Kill 一个子进程
有几个命令会无限期地运行,或者需要明确的信号才能停止。
例如,如果我们使用 python3 -m http.server 启动 Web 服务器或执行 sleep 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:
当您想要限制运行命令所花费的时间或想要创建回退以防命令未按时返回结果时,终止子进程很有用。
来源:https://blog.csdn.net/yuzhou_1shu/article/details/130725713
猜你喜欢
- 一、Pytest概念Pytest 是 Python 的一种单元测试框架,与 Python 自带的 unittest 测试框架类似,但是比 u
- 本文实例讲述了Python lambda表达式用法。分享给大家供大家参考,具体如下:lambda表达式,通常是在需要一个函数,但是又不想费神
- 下面就是我们的authenticate.asp页面,在这里,将用户的信息收集起来,连同最初的URL一起传到一个识别用户身份的页面中。我们可用
- 但是,当一本书学过之后,对一般的技术和函数都有了印象,突然想要查找某个函数的实例代码时,却感到很困难,因为一本书的源代码目录很长,往往有几十
- 在开始聊我在阿里四个月的网页推广设计之前,我想先来说说我对平面设计和网页设计的认识。它们之间的交集。它们都是集艺术创作、电脑技术和数字技术于
- python将ansible配置转为json格式实例代码ansible的配置文件举例如下,这种配置文件不利于在前端的展现,因此,我们用一段简
- 前言之前看过一遍的python教程,真的是自己看过一遍,python的程序能看懂,但是很难去实现。比较困难的自己实现一些代码,找工作原因,自
- 本文实例分析了python的私有属性和方法。分享给大家供大家参考。具体实现方法如下:python默认的成员函数和成员变量都是公开的,并且没有
- 同由其他技术驱动的应用一样,在相同的Web服务器上运行Django应用也是可行的。 最简单直接的办法就是利用Apaches配置文件httpd
- django-allauth是集成的Django应用程序,用于解决网站身份验证,用户的注册登录及账户管理,以及第三方(社交)账户的身份验证。
- 1.简介MongoDB是一个基于分布式文件存储的文档数据库,可以说是非关系型(NoSQL,Not Only SQL)数据库中比较像关系型数据
- 本文实例讲述了Python 闭包,函数分隔作用域,nonlocal声明非局部变量操作。分享给大家供大家参考,具体如下:实例对象也可以实现闭包
- 什么是python的装饰器?网络上的定义:装饰器就是一函数,用来包装函数的函数,用来修饰原函数,将其重新赋值给原来的标识符,并永久的丧失原函
- 本文实例讲述了python迭代器的简单用法,分享给大家供大家参考。具体分析如下:生成器表达式是用来生成函数调用时序列参数的一种迭代器写法生成
- 前言想要使用摄像头实现一个多人姿态识别环境安装下载并安装 Anaconda官网连接 https://anaconda.cloud/insta
- 本文实例讲述了Python简单网络编程。分享给大家供大家参考,具体如下:内容目录1. 客户端(client.py)2. 服务端(server
- 函数:split()例子我们想要将以下字符串rule进行拆分。字符串表示的是一个规则,由“…”得到“…”。我们需要将规则中的条件属性与取值分
- 一、如果models.py文件为时:timestamp = models.DateTimeField('保存日期')会提示:
- vue动态绑定class练习。:class=“{ ‘类名1':条件表达式,‘类名2':条件表达式… }”<templa
- php服务端与客户端交互、提供开放api时,通常需要对敏感的部分api数据传输进行数据加密,这时候rsa非对称加密就能派上用处了,下面通过一