1. 概述

golang 下的 os/exec 包执行外部命令包执行外部命令。它包装了 os.StartProcess 函数以便更容易的修正输入和输出,使用管道连接I/O,以及作其它的一些调整。

C 语言或者其他语言中的“系统”库调用不同, os/exec 包并不调用系统 shell ,也不展开任何 glob (正则匹配)模式,也不处理通常由 shell 完成的其他扩展、管道或重定向。

2. 相关函数

2.1 Variables

var ErrNotFound = errors.New("executable file not found in $PATH")

如果路径搜索没有找到可执行文件时,就会返回本错误。

2.2 type Error

type Error struct {Name stringErr  error
}

Error类型记录执行失败的程序名和失败的原因。对应的方法如下:

func (e *Error) Error() string

2.3 type ExitError

type ExitError struct {*os.ProcessState
}

ExitError 报告某个命令的一次未成功的返回。对应的方法如下:

func (e *ExitError) Error() string

2.4 func LookPath

func LookPath(file string) (string, error)

2.5 type cmd

    func Command(name string, arg ...string) *Cmdfunc (c *Cmd) StdinPipe() (io.WriteCloser, error)func (c *Cmd) StdoutPipe() (io.ReadCloser, error)func (c *Cmd) StderrPipe() (io.ReadCloser, error)func (c *Cmd) Run() errorfunc (c *Cmd) Start() errorfunc (c *Cmd) Wait() errorfunc (c *Cmd) Output() ([]byte, error)func (c *Cmd) CombinedOutput() ([]byte, error)

3. 函数详解

3.1 func LookPath

函数定义

func LookPath(file string) (string, error)

在环境变量 PATH 指定的目录中搜索可执行文件,如 file 中有斜杠,则直接根据绝对路径或者相对本目录的相对路径去查找。返回完整路径或者相对于当前目录的一个相对路径。

默认在系统的环境变量里查找给定的可执行命令文件。

使用示例:

package mainimport ("fmt""os/exec"
)func main() {f, err := exec.LookPath("pwd")if err != nil {fmt.Println("Not find the cmd")}fmt.Printf("Binary file path is %s", f) // /bin/pwd
}

3.2 Cmd 结构体

Cmd 代表一个正在准备或者在执行中的外部命令。

type Cmd struct {// Path是将要执行的命令的路径。//// 该字段不能为空,如为相对路径会相对于Dir字段。Path string// Args保管命令的参数,包括命令名作为第一个参数;如果为空切片或者nil,相当于无参数命令。//// 典型用法下,Path和Args都应被Command函数设定。Args []string// Env指定进程的环境,如为nil,则是在当前进程的环境下执行。Env []string// Dir指定命令的工作目录。如为空字符串,会在调用者的进程当前目录下执行。Dir string// Stdin指定进程的标准输入,如为nil,进程会从空设备读取(os.DevNull)Stdin io.Reader// Stdout和Stderr指定进程的标准输出和标准错误输出。//// 如果任一个为nil,Run方法会将对应的文件描述符关联到空设备(os.DevNull)//// 如果两个字段相同,同一时间最多有一个线程可以写入。Stdout io.WriterStderr io.Writer// ExtraFiles指定额外被新进程继承的已打开文件流,不包括标准输入、标准输出、标准错误输出。// 如果本字段非nil,entry i会变成文件描述符3+i。//// BUG: 在OS X 10.6系统中,子进程可能会继承不期望的文件描述符。// http://golang.org/issue/2603ExtraFiles []*os.File// SysProcAttr保管可选的、各操作系统特定的sys执行属性。// Run方法会将它作为os.ProcAttr的Sys字段传递给os.StartProcess函数。SysProcAttr *syscall.SysProcAttr// Process是底层的,只执行一次的进程。Process *os.Process// ProcessState包含一个已经存在的进程的信息,只有在调用Wait或Run后才可用。ProcessState *os.ProcessState// 内含隐藏或非导出字段
}

注: exec 在执行调用系统命令时,会先对需要执行的操作进行一次封装,然后再执行。封装后的命令对象具有以上 struct 属性。而封装方式即使用下边的 Command 函数。

3.3 func Command

func Command(name string, arg ...string) *Cmd

函数返回一个 *Cmd ,用于使用给出的参数执行 name 指定的程序。返回值只设定了 PathArgs 两个参数。
如果 name 不含路径分隔符,将使用 LookPath 获取完整路径;否则直接使用 name 。参数 arg 不应包含命令名。

使用示例:

func main() {cmd := exec.Command("go", "version")fmt.Printf("cmd.Path is %s, cmd.Args is %s", cmd.Path, cmd.Args)// cmd.Path is /usr/local/go/bin/go, cmd.Args is [go version]
}

注意:以上操作只会将命令进行封装,相当于告诉系统将进行哪些操作,但是执行时无法获取相关信息。所以说Cmd 代表一个正在准备或者在执行中的外部命令。

3.4 func (*Cmd) Run

func (c *Cmd) Run() error

Run 执行 c 包含的命令,并阻塞直到完成。

  • 如果命令成功执行, stdinstdoutstderr 的转交没有问题,并且返回状态码为 0,方法的返回值为 nil
  • 如果命令没有执行或者执行失败,会返回 *ExitError 类型的错误;否则返回的 error 可能是表示 I/O 问题。

使用示例:

func main() {cmd := exec.Command("go", "version")fmt.Printf("cmd.Path is %s, cmd.Args is %s", cmd.Path, cmd.Args)err := cmd.Run()if err != nil {fmt.Println("cmd run failed")}}

有输出结果值:

command := "echo hello"
cmd := exec.Command("/bin/bash", "-c", command)
// cmd := exec.Command("sh", "-c", command)
bytes, err := cmd.Output()
if err != nil {log.Println(err)
}
resp := string(bytes)
log.Println(resp)

没有输出结果值:

command := "echo hello"
cmd := exec.Command("/bin/bash", "-c", command)
// cmd := exec.Command("sh", "-c", command)
err = cmd.Run()

3.5 func (*Cmd) Start

func (c *Cmd) Start() error

Start 开始执行 c 包含的命令,但并不会等待该命令完成即返回。 Wait 方法会返回命令的返回状态码并在命令返回后释放相关的资源。

3.6 func (*Cmd) Wait

func (c *Cmd) Wait() error

Wait 会阻塞直到该命令执行完成,该命令必须是被 Start 方法开始执行的

  • 如果命令成功执行, stdinstdoutstderr 的转交没有问题,并且返回状态码为 0,方法的返回值为 nil
  • 如果命令没有执行或者执行失败,会返回 *ExitError 类型的错误;否则返回的 error 可能是表示 I/O 问题。 Wait 方法会在命令返回后释放相关的资源。

使用示例:

func main() {cmd := exec.Command("go", "version")fmt.Printf("cmd.Path is %s, cmd.Args is %s", cmd.Path, cmd.Args)err := cmd.Start()if err != nil {fmt.Println("cmd run failed")}err = cmd.Wait()if err != nil {fmt.Println("cmd wait failed")}}

3.7 Start 和 Run 的区别

使用示例:

func main() {cmd := exec.Command("sleep", "5")// err := cmd.Run() 执行 Run 会立即阻塞等待 5 秒种err := cmd.Start()if err != nil {fmt.Println("cmd run failed")}fmt.Println("waiting for cmd ...")// 执行 Start() 上面的打印会先执行,然后在 Wait() 方法阻塞等待 5serr = cmd.Wait()if err != nil {fmt.Println("cmd wait failed")}}

注意:
一个命令只能使用 Start() 或者 Run() 中的一个启动命令,不能两个同时使用。

3.8 func CombinedOutput

func (c *Cmd) CombinedOutput() ([]byte, error)

执行命令并返回标准输出和错误输出合并的切片。

3.9 func Output

func (c *Cmd) Output() ([]byte, error)

执行命令并返回标准输出的切片。

使用示例:

func main() {cmd := exec.Command("ls", "-a", "-l")// err := cmd.Start()// if err != nil {//     fmt.Println("cmd run failed")// }// fmt.Println("waiting for cmd ...")// err = cmd.Wait()// if err != nil {//     fmt.Println("cmd wait failed")// }out, err := cmd.Output()if err != nil {fmt.Println("cmd Output failed ", err)}fmt.Printf("out is %s", out)
}

注意:

  1. Output()CombinedOutput() 不能够同时使用,因为 command 的标准输出只能有一个,同时使用的话便会定义了两个,便会报错;
  2. CommandOutput 之间不需要再增加 StartWait 方法,否则也会报错;

3.10 func (*Cmd) StdinPipe

func (c *Cmd) StdinPipe() (io.WriteCloser, error)

StdinPipe 方法返回一个在命令 Start 后与命令标准输入关联的管道。 Wait 方法获知命令结束后会关闭这个管道。必要时调用者可以调用 Close 方法来强行关闭管道,例如命令在输入关闭后才会执行返回时需要显式关闭管道。

3.11 func (*Cmd) StdoutPipe

func (c *Cmd) StdoutPipe() (io.ReadCloser, error)

StdoutPipe 方法返回一个在命令 Start 后与命令标准输出关联的管道。 Wait 方法获知命令结束后会关闭这个管道,一般不需要显式的关闭该管道。但是在从管道读取完全部数据之前调用 Wait 是错误的;同样使用 StdoutPipe 方法时调用 Run 函数也是错误的。

3.12 func (*Cmd) StderrPipe

func (c *Cmd) StderrPipe() (io.ReadCloser, error)

StderrPipe 方法返回一个在命令 Start 后与命令标准错误输出关联的管道。 Wait 方法获知命令结束后会关闭这个管道,一般不需要显式的关闭该管道。但是在从管道读取完全部数据之前调用 Wait 是错误的;同样使用 StderrPipe 方法时调用 Run 函数也是错误的。

参考资料:

  1. https://blog.csdn.net/u013256816/article/details/99670090
  2. https://studygolang.com/static/pkgdoc/pkg/os_exec.htm
  3. https://www.cnblogs.com/sunailong/p/7852216.html

Go 学习笔记(43)— Go 标准库之 os/exec(执行外部命令、非阻塞等待、阻塞等待、命令输出)相关推荐

  1. Python学习笔记: Python 标准库概览

    本文来自:入门指南 开胃菜参考:开胃菜 使用Python解释器:使用Python解释器 本文对Python的简介:Python 简介 Python流程介绍:深入Python 流程 Python数据结构 ...

  2. python基础教程_学习笔记14:标准库:一些最爱——re

    标准库:一些最爱 re re模块包括对正則表達式的支持,由于以前系统学习过正則表達式,所以基础内容略过,直接看python对于正則表達式的支持. 正則表達式的学习,见<Mastering Reg ...

  3. python基础课程_学习笔记13:标准库:有些收藏夹——sys

    标准库:有些收藏夹 sys sys这个模块可以让你访问和python解释器联系紧密的变量和函数. sys模块中一些重要的函数和变量 函数/变量 描写叙述 argv 命令行參数,包含脚本名称 exit( ...

  4. Python学习笔记: Python 标准库概览二

    本文来自:入门指南 开胃菜参考:开胃菜 使用Python解释器:使用Python解释器 本文对Python的简介:Python 简介 Python流程介绍:深入Python 流程 Python数据结构 ...

  5. python标准库os.path中_Python零基础入门学习19:常用标准库之os.path子库

    注:本文所有代码均经过Python 3.7实际运行检验,保证其严谨性. 本文阅读时间约为3~5分钟. os库是Python标准库,包含几百个函数.它能处理与系统相关的常用路径操作.进程管理.环境参数等 ...

  6. Python学习笔记17:标准库之数学相关(math包,random包)

    前面几节看得真心累.如今先来点简单easy理解的内容. 一 math包 math包主要处理数学相关的运算. 常数 math.e   # 自然常数e math.pi  # 圆周率pi 运算函数 math ...

  7. Python学习笔记14:标准库之信号量(signal包)

    signal包负责在Python程序内部处理信号.典型的操作包含预设信号处理函数,暂停并等待信号,以及定时发出SIGALRM等. 要注意,signal包主要是针对UNIX平台(比方Linux, MAC ...

  8. Javaweb学习笔记(JSP标准标签库)

    Javaweb学习笔记(JSP标准标签库) JSTL入门 安装和测试JSTL JSTL中的Core标签库 < c:out>标签 标签 标签 < c:catch>标签 标签 标签 ...

  9. STM32CUBEMX入门学习笔记3:HAL库以及STM32CUBE相关资料

    STM32CUBEMX入门学习笔记3:HAL库以及STM32CUBE相关资料 微雪课堂:http://www.waveshare.net/study/article-629-1.html 之前的正点原 ...

最新文章

  1. Python:CrawlSpiders
  2. 企业安全体系建设方案设计(内附案例)
  3. 几乎死循环的存储过程
  4. HLS视频协议第一弹--centos下面配置ffmpeg,segmenter以适应hls切片需要
  5. go 切片slice删除元素的方法
  6. feach同步 git_git fetch 更新远程代码到本地仓库
  7. 实现后台高级查询(高级版)
  8. java response文件流下载,后缀名称设置
  9. 360浏览器不能打开CSDN登陆页面
  10. Visual Studio各组件说明
  11. 主成分分析R语言实现
  12. java 小型超市管理系统_基于jsp的小型超市管理系统-JavaEE实现小型超市管理系统 - java项目源码...
  13. 计算机网络技术评估与备选方案,创业学复习提纲
  14. python爬虫,从hao123爬取网址信息
  15. 扫除知识共享障碍,天翎知识文档管理系统+群晖NAS一体化解决方案
  16. 论文笔记:BING and BING++(论文+程序)
  17. CentOS7本地源yum配置
  18. 后端的一个刚毕业的小伙子老早完成了架构和服务端逻辑,接口洋洋洒洒列了出来。。。...
  19. docker--swarm集群管理(结合harbor仓库、docker stack部署、Portainer可视化)
  20. 2023 节假日 生成sql脚本 ORACLE

热门文章

  1. kotlin重写构造方法编译报错:Primary constructor call expected
  2. 2022-2028年中国微藻行业市场调查研究及前瞻分析报告
  3. Apriori算法通俗详解_fpgrowth_关联
  4. python编程问题---第一次
  5. LeetCode简单题之按奇偶排序数组 II
  6. 激光雷达Lidar Architecture and Lidar Design(下)
  7. 人脸识别数据集精粹(下)
  8. System.err: java.lang.UnsatisfiedLinkError: dlopen failed: library “libc++_shared.so“ not found
  9. JavaScript_day01
  10. MyBatis if标签的用法