os/exec 执行命令、管道
在windows执行命令
cmd0 := exec.Command("cmd.exe","/C", "dir")
前两个参数是固定的,后面+命令
在linux中
cmd0 := exec.Command("ps","aux")
也可以加入一些参数
cmd0 := exec.Command("echo","-n", "你好")
使用Command 方法可以返回一个 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.Writer Stderr io.Writer // ExtraFiles指定额外被新进程继承的已打开文件流,不包括标准输入、标准输出、标准错误输出。 // 如果本字段非nil,entry i会变成文件描述符3+i。 // // BUG: 在OS X 10.6系统中,子进程可能会继承不期望的文件描述符。 // http://golang.org/issue/2603 ExtraFiles []*os.File // SysProcAttr保管可选的、各操作系统特定的sys执行属性。 // Run方法会将它作为os.ProcAttr的Sys字段传递给os.StartProcess函数。 SysProcAttr *syscall.SysProcAttr // Process是底层的,只执行一次的进程。 Process *os.Process // ProcessState包含一个已经存在的进程的信息,只有在调用Wait或Run后才可用。 ProcessState *os.ProcessState // 内含隐藏或非导出字段 }
可以通过这个结构体的 方法获取 标准输出 、标准输出、标准错误输出的管道
ioWriterCloser ,err := cmd0.StdinPipe() ioReaderCloser,err := cmd0.StderrPipe() ioReaderCloser,err := cmd0.StdoutPipe()
管道方法返回 两种接口。
我们可以利用接口获取数据、写入其他命令
获取数据
cmd0 := exec.Command("cmd.exe","/C", "dir") ioR ,err := cmd0.StderrPipe() if err != nil { panic("err") } r := bufio.NewReader(ioR) l ,_,err := r.ReadLine() if err != nil { panic("err") }
也可以通过 返回ioReader 接口 直接读数据,读到结尾判断EOF就可以了。
将一个命令的输出作为另外一个命令的输入 相当于 #ps aux | grep apipe
cmd1 := exec.Command("ps","aux") cmd2 := exec.Command("grep","apipe") var outPutBuf1 bytes.Buffer //指定命令的标准输出 cmd1.Stdout = &outPutBuf1 //指定cmd2的标准输入 cmd2.Stdin = &outPutBuf1
管道还有os.Pipe() 、io.Pipe() 后者是基于内存的有原子性保障的单独管道
还有就是一个很关键的字段 cmd.ExtraFiles
可以像要打开的新进程中添加文件流
cmd.ExtraFiles = []*os.File{f}
文件流使用os.NewFile(3,"") 打开 ,因为前几个文件描述符 0、1、2 默认为 标准输入、标准输出、标准错误输出