Go基礎篇【第5篇】: 內置庫模塊 exec

Package exec runs external commands. It wraps os.StartProcess to make it easier to remap stdin and stdout, connect I/O with pipes, and do other adjustments.git

Unlike the "system" library call from C and other languages, the os/exec package intentionally does not invoke the system shell and does not expand any glob patterns or handle other expansions, pipelines, or redirections typically done by shells. The package behaves more like C's "exec" family of functions. To expand glob patterns, either call the shell directly, taking care to escape any dangerous input, or use the path/filepath package's Glob function. To expand environment variables, use package os's ExpandEnv.github

Note that the examples in this package assume a Unix system. They may not run on Windows, and they do not run in the Go Playground used by golang.org and godoc.org.golang

func LookPath

func LookPath(file string) (string, error)

在環境變量PATH指定的目錄中搜索可執行文件,如file中有斜槓,則只在當前目錄搜索。shell

即:默認在系統的環境變量裏查找給定的可執行命令文件,若是查找到返回路徑,不然報錯,unix是$PATH,windows是$PATH$。可提供相對路徑下進行查找,並返回相對路徑windows

type 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
    // 內含隱藏或非導出字段
}

Cmd表明一個正在準備或者在執行中的外部命令。函數

注:exec在執行調用系統命令時,會先對須要執行的操做進行一次封裝,而後在執行。封裝後的命令對象具備以上struct屬性。而封裝方式即便用下邊的command函數。ui

func Command

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

函數返回一個*Cmd,用於使用給出的參數執行name指定的程序。返回值只設定了Path和Args兩個參數。this

若是name不含路徑分隔符(若是不是相對路徑),將使用LookPath獲取完整路徑(就是用默認的全局變量路徑);不然直接使用name。參數arg不該包含命令名。spa

cmd := exec.Command("go","version")
fmt.Println(cmd.Args, cmd.Path)

注:在調用命令執行封裝時,若是不提供相對路徑,系統會使用LookPath獲取完整路徑;即這裏能夠給一個相對路徑。操作系統

以上操做只會將命令進行封裝,至關於告訴系統將進行哪些操做,可是執行時沒法獲取相關信息,所以咱們還須要鏈接到命令執行時相關的輸入輸出pipe。################################################################################################

咱們能夠經過指定一個對象鏈接到對應的管道進行傳輸參數(stdinpipe),獲取輸出(stdoutpipe),獲取錯誤(stderrpipe)

func (*Cmd) StdinPipe

func (c *Cmd) StdinPipe() (io.WriteCloser, error)  //err 返回的是執行函數時的錯誤
package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    cmd := exec.Command("cat")
    stdin, err := cmd.StdinPipe()       //指定stdin鏈接StdinPipe,而後操做stdin就實現了對command的參數傳遞
    if err != nil {
        fmt.Println(err)
    }
    _, err = stdin.Write([]byte("tmp.txt"))   //字節切片
    if err != nil {
        fmt.Println(err)
    }
    stdin.Close()
    cmd.Stdout = os.Stdout     //終端標準輸出tmp.txt
    cmd.Start()
}

StdinPipe方法返回一個在命令Start後與命令標準輸入關聯的管道。Wait方法獲知命令結束後會關閉這個管道。必要時調用者能夠調用Close方法來強行關閉管道,例如命令在輸入關閉後纔會執行返回時須要顯式關閉管道。

func (*Cmd) StdoutPipe

func (c *Cmd) StdoutPipe() (io.ReadCloser, error)    //err 返回的是執行函數時的錯誤
func main() {
    cmd := exec.Command("ls")
    stdout, err := cmd.StdoutPipe()  //指向cmd命令的stdout,而後就能夠從stdout讀出信息
    cmd.Start()
    content, err := ioutil.ReadAll(stdout)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(content))     //輸出ls命令查看到的內容
}

StdoutPipe方法返回一個在命令Start後與命令標準輸出關聯的管道。Wait方法獲知命令結束後會關閉這個管道,通常不須要顯式的關閉該管道。可是在從管道讀取徹底部數據以前調用Wait是錯誤的;一樣使用StdoutPipe方法時調用Run函數也是錯誤的。

func (*Cmd) StderrPipe

func (c *Cmd) StderrPipe() (io.ReadCloser, error)   //err 返回的是執行函數時的錯誤
import (
"fmt"
"io/ioutil"
"os/exec"
)

func main() {
    c := exec.Command("mv", "hello")
    i, err := c.StderrPipe()
    if err != nil {
        fmt.Printf("Error: %s\n", err)
        return
    }
    if err = c.Start(); err != nil {    //表示命令正確執行了
        fmt.Printf("Error: %s\n", err)
    }
    b, _ := ioutil.ReadAll(i)        //讀取命令執行的返回結果(命令執行結果的錯誤信息)
    if err := c.Wait(); err != nil {
        fmt.Printf("Error: %s\n", err)   //Error: exit status 1 mv: missing file argument Try `mv --help' for more information.
    }                                                                 
    fmt.Println(string(b))
}

StderrPipe方法返回一個在命令Start後與命令標準錯誤輸出關聯的管道。Wait方法獲知命令結束後會關閉這個管道,通常不須要顯式的關閉該管道。可是在從管道讀取徹底部數據以前調用Wait是錯誤的;一樣使用StderrPipe方法時調用Run函數也是錯誤的

#################################################################

func (*Cmd) Run 

func (c *Cmd) Run() error

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

若是命令成功執行,stdin、stdout、stderr的轉交沒有問題,而且返回狀態碼爲0,方法的返回值爲nil【執行Run函數的返回狀態,正確執行Run函數,並不表明正確執行了命令】;若是函數沒有執行或者執行失敗,會返回*ExitError類型的錯誤;不然返回的error多是表示I/O問題。

即:該命令只會執行且阻塞到執行結束,若是執行函數有錯則返回報錯信息,沒錯則返回nil,並不會返回執行結果。

func (*Cmd) Start

func (c *Cmd) Start() error

Start開始執行c包含的命令,但並不會等待該命令完成即返回。Wait方法會返回命令的返回狀態碼並在命令返回後釋放相關的資源。

Example

func (*Cmd) Wait

func (c *Cmd) Wait() error

Wait會阻塞直到該命令執行完成,該命令必須是被Start方法開始執行的。

若是命令成功執行,stdin、stdout、stderr的轉交沒有問題,而且返回狀態碼爲0,方法的返回值爲nil;若是命令沒有執行或者執行失敗,會返回*ExitError類型的錯誤;不然返回的error多是表示I/O問題。Wait方法會在命令返回後釋放相關的資源。

func (*Cmd) Output

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

執行命令並返回標準輸出的切片。不用經過pipe方式獲取命令的執行結果

import (
"fmt"
"os/exec"
)

func main() {
    c, err := exec.Command("date").Output() if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(c)) //    Sat Jan 4 17:07:36 2014 這個是標準庫裏的例子
}

func (*Cmd) CombinedOutput

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

執行命令並返回標準輸出和錯誤輸出合併的切片。

相關文章
相關標籤/搜索