Go 学习笔记(43)— Go 标准库之 os/exec(执行外部命令、非阻塞等待、阻塞等待、命令输出)
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
指定的程序。返回值只设定了 Path
和 Args
两个参数。
如果 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
包含的命令,并阻塞直到完成。
- 如果命令成功执行,
stdin
、stdout
、stderr
的转交没有问题,并且返回状态码为 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
方法开始执行的。
- 如果命令成功执行,
stdin
、stdout
、stderr
的转交没有问题,并且返回状态码为 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)
}
注意:
Output()
和CombinedOutput()
不能够同时使用,因为command
的标准输出只能有一个,同时使用的话便会定义了两个,便会报错;Command
和Output
之间不需要再增加Start
、Wait
方法,否则也会报错;
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
函数也是错误的。
参考资料:
- https://blog.csdn.net/u013256816/article/details/99670090
- https://studygolang.com/static/pkgdoc/pkg/os_exec.htm
- https://www.cnblogs.com/sunailong/p/7852216.html
Go 学习笔记(43)— Go 标准库之 os/exec(执行外部命令、非阻塞等待、阻塞等待、命令输出)相关推荐
- Python学习笔记: Python 标准库概览
本文来自:入门指南 开胃菜参考:开胃菜 使用Python解释器:使用Python解释器 本文对Python的简介:Python 简介 Python流程介绍:深入Python 流程 Python数据结构 ...
- python基础教程_学习笔记14:标准库:一些最爱——re
标准库:一些最爱 re re模块包括对正則表達式的支持,由于以前系统学习过正則表達式,所以基础内容略过,直接看python对于正則表達式的支持. 正則表達式的学习,见<Mastering Reg ...
- python基础课程_学习笔记13:标准库:有些收藏夹——sys
标准库:有些收藏夹 sys sys这个模块可以让你访问和python解释器联系紧密的变量和函数. sys模块中一些重要的函数和变量 函数/变量 描写叙述 argv 命令行參数,包含脚本名称 exit( ...
- Python学习笔记: Python 标准库概览二
本文来自:入门指南 开胃菜参考:开胃菜 使用Python解释器:使用Python解释器 本文对Python的简介:Python 简介 Python流程介绍:深入Python 流程 Python数据结构 ...
- python标准库os.path中_Python零基础入门学习19:常用标准库之os.path子库
注:本文所有代码均经过Python 3.7实际运行检验,保证其严谨性. 本文阅读时间约为3~5分钟. os库是Python标准库,包含几百个函数.它能处理与系统相关的常用路径操作.进程管理.环境参数等 ...
- Python学习笔记17:标准库之数学相关(math包,random包)
前面几节看得真心累.如今先来点简单easy理解的内容. 一 math包 math包主要处理数学相关的运算. 常数 math.e # 自然常数e math.pi # 圆周率pi 运算函数 math ...
- Python学习笔记14:标准库之信号量(signal包)
signal包负责在Python程序内部处理信号.典型的操作包含预设信号处理函数,暂停并等待信号,以及定时发出SIGALRM等. 要注意,signal包主要是针对UNIX平台(比方Linux, MAC ...
- Javaweb学习笔记(JSP标准标签库)
Javaweb学习笔记(JSP标准标签库) JSTL入门 安装和测试JSTL JSTL中的Core标签库 < c:out>标签 标签 标签 < c:catch>标签 标签 标签 ...
- STM32CUBEMX入门学习笔记3:HAL库以及STM32CUBE相关资料
STM32CUBEMX入门学习笔记3:HAL库以及STM32CUBE相关资料 微雪课堂:http://www.waveshare.net/study/article-629-1.html 之前的正点原 ...
最新文章
- Python:CrawlSpiders
- 企业安全体系建设方案设计(内附案例)
- 几乎死循环的存储过程
- HLS视频协议第一弹--centos下面配置ffmpeg,segmenter以适应hls切片需要
- go 切片slice删除元素的方法
- feach同步 git_git fetch 更新远程代码到本地仓库
- 实现后台高级查询(高级版)
- java response文件流下载,后缀名称设置
- 360浏览器不能打开CSDN登陆页面
- Visual Studio各组件说明
- 主成分分析R语言实现
- java 小型超市管理系统_基于jsp的小型超市管理系统-JavaEE实现小型超市管理系统 - java项目源码...
- 计算机网络技术评估与备选方案,创业学复习提纲
- python爬虫,从hao123爬取网址信息
- 扫除知识共享障碍,天翎知识文档管理系统+群晖NAS一体化解决方案
- 论文笔记:BING and BING++(论文+程序)
- CentOS7本地源yum配置
- 后端的一个刚毕业的小伙子老早完成了架构和服务端逻辑,接口洋洋洒洒列了出来。。。...
- docker--swarm集群管理(结合harbor仓库、docker stack部署、Portainer可视化)
- 2023 节假日 生成sql脚本 ORACLE
热门文章
- kotlin重写构造方法编译报错:Primary constructor call expected
- 2022-2028年中国微藻行业市场调查研究及前瞻分析报告
- Apriori算法通俗详解_fpgrowth_关联
- python编程问题---第一次
- LeetCode简单题之按奇偶排序数组 II
- 激光雷达Lidar Architecture and Lidar Design(下)
- 人脸识别数据集精粹(下)
- System.err: java.lang.UnsatisfiedLinkError: dlopen failed: library “libc++_shared.so“ not found
- JavaScript_day01
- MyBatis if标签的用法