文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Golang怎么应用执行Shell命令

2023-07-05 12:56

关注

今天小编给大家分享一下Golang怎么应用执行Shell命令的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

exec包

使用官方os/exec包可以执行外部命令,当你执行shell命令,是需要在Go应用的外部运行代码,因此需要这些命令在子进程中运行。如下图所示:

Golang怎么应用执行Shell命令

每个命令在Go应用中作为子进程运行,并暴露stdin和stdout属性,我们可以使用它们读写进程数据。

运行基本Shell命令

运行简单命令并从它的输出中读取数据,通过创建*exec.Cmd实例实现。在下面示例中,使用ls列出当前目录下的文件,并从代码中打印其输出:

// create a new *Cmd instance// here we pass the command as the first argument and the arguments to pass to the command as the// remaining arguments in the functioncmd := exec.Command("ls", "./")// The `Output` method executes the command and// collects the output, returning its valueout, err := cmd.Output()if err != nil {  // if there was any error, print it here  fmt.Println("could not run command: ", err)}// otherwise, print the output from running the commandfmt.Println("Output: ", string(out))

因为在当前目录下运行程序,因此输出项目根目录下文件:

> go run shellcommands/main.goOutput:  LICENSEREADME.mdcommand.go

Golang怎么应用执行Shell命令

当运行exec,程序没有产生shell,而是直接运行给定命令,这意味着不会进行任何基于shell的处理,比如glob模式或扩展。举例,当运行ls ./*.md命令,并不会如我们在那个shell中运行命令一样输出readme.md

执行长时间运行命令

前面示例执行ls命令立刻返回结果,但当命令输出是连续的、或需要很长时间执行时会怎样呢?举例,运行ping命令,会周期性获得连续结果:

ping www.baidu.com PING www.a.shifen.com (36.152.44.95) 56(84) bytes of data.64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=1 ttl=128 time=11.1 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=2 ttl=128 time=58.8 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=3 ttl=128 time=28.2 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=4 ttl=128 time=11.1 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=5 ttl=128 time=11.5 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=6 ttl=128 time=53.6 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=7 ttl=128 time=10.2 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=8 ttl=128 time=10.4 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=9 ttl=128 time=15.8 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=10 ttl=128 time=16.5 ms64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=11 ttl=128 time=10.9 ms^C64 bytes from 36.152.44.95: icmp_seq=12 ttl=128 time=9.92 ms

如果尝试使用cmd.Output执行这类命令,则不会获得任何结果,因为Output方法等待命令执行结束,而ping无限期执行。因此需要自定义Stdout属性去读取连续输出:

cmd := exec.Command("ping", "google.com")// pipe the commands output to the applications// standard outputcmd.Stdout = os.Stdout// Run still runs the command and waits for completion// but the output is instantly piped to Stdoutif err := cmd.Run(); err != nil {  fmt.Println("could not run command: ", err)}

再次运行程序,输出结果于Shell中执行类似。

通过直接分配Stdout属性,我们可以在整个命令生命周期中捕获输出,并在接收到输出后立即对其进行处理。进程间io交互如下图所示:

Golang怎么应用执行Shell命令

自定义写输出

代替使用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}

现在给命令输出赋值自定义写输出实例:

cmd.Stdout = customOutput{}

再次运行程序,会获得下面的输出。

使用Stdin给命令传递输入

前面示例没有给命令任何输入(或提供有限输入作为参数),大多数场景中通过Stdin流传递输入信息。典型的示例为grep命令,可以通过管道从一个命令串给另一个命令:

➜  ~ echo "1. pear\n2. grapes\n3. apple\n4. banana\n" | grep apple3. apple

这里echo的输出作为stdin传给grep,输入一组水果,通过grep过滤仅输出apple.

*Cmd实例提供了输入流用于写入,下面实例使用它传递输入给grep子进程:

cmd := exec.Command("grep", "apple")// Create a new pipe, which gives us a reader/writer pairreader, writer := io.Pipe()// assign the reader to Stdin for the commandcmd.Stdin = reader// the output is printed to the consolecmd.Stdout = os.Stdoutgo 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)}

输出结果:

apple

Golang怎么应用执行Shell命令

结束子进程

有一些命令无限期运行,需要能够显示信号去结束。举例,如果使用python3 -m http.server运行web服务或sleep 10000,则子进程会运行很长时间或无限期运行。

要停止进程,需要从应用中发送kill信号,可以通过给命令增加上下文实例实现。如果上下文取消,则命令也会终止执行:

ctx := context.Background()// The context now times out after 1 second// alternately, we can call `cancel()` to terminate immediatelyctx, _ = context.WithTimeout(ctx, 1*time.Second)// sleep 10 second cmd := exec.CommandContext(ctx, "sleep", "10")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:  

当需要在有限时间内运行命令或在一定时间内命令没有返回结果则执行备用逻辑。

以上就是“Golang怎么应用执行Shell命令”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯