1. 程式人生 > 實用技巧 >go channel 概述 - 管道

go channel 概述 - 管道

概述

unix/linux OS 的一個程序的輸出可以是另一個程序的輸入,這些程序使用stdin與stdout裝置作為通道,在程序之間傳遞資料。

同樣的,GO中有io.Reader與io.Writer兩個介面,如果要對一個裝置進行讀/寫,呼叫實現了這兩個介面的方法即可。

GO對管道的支援

func t1()  {
    cmd0 := exec.Command("echo","-n","how are you")
    fmt.Println(cmd0)
}

exec.Command返回的物件的幾個主要方法:

    // Stdin specifies the process's standard input.
    
// // If Stdin is nil, the process reads from the null device (os.DevNull). // // If Stdin is an *os.File, the process's standard input is connected // directly to that file. // // Otherwise, during the execution of the command a separate // goroutine reads from Stdin and delivers that data to the command
// over a pipe. In this case, Wait does not complete until the goroutine // stops copying, either because it has reached the end of Stdin // (EOF or a read error) or because writing to the pipe returned an error. Stdin io.Reader // Stdout and Stderr specify the process's standard output and error.
// // If either is nil, Run connects the corresponding file descriptor // to the null device (os.DevNull). // // If either is an *os.File, the corresponding output from the process // is connected directly to that file. // // Otherwise, during the execution of the command a separate goroutine // reads from the process over a pipe and delivers that data to the // corresponding Writer. In this case, Wait does not complete until the // goroutine reaches EOF or encounters an error. // // If Stdout and Stderr are the same writer, and have a type that can // be compared with ==, at most one goroutine at a time will call Write. Stdout io.Writer Stderr io.Writer

示例

/*
引數傳入的是命令組
通過buffer一次次讀取返回結果,不怕返回的資料量大
如果命令是shell那樣有|管道符,則使用Pip方法即可
 */
func PipCmd(cmd []string,useBufferIO... bool) string {
    useBufferedIO := false

    ll := len(useBufferIO)
    if ll > 0 {
        useBufferedIO = useBufferIO[0]
    }
    cmd0 := Command(cmd)
    stdout0, err := cmd0.StdoutPipe()
    if err != nil {
        fmt.Printf("Error: Couldn't obtain the stdout pipe for command : %s\n", err)
        return ""
    }
    defer stdout0.Close()
    if err := cmd0.Start(); err != nil {
        fmt.Printf("Error: The command  can not be startup: %s\n", err)
        return ""
    }
    if !useBufferedIO {
        var outputBuf0 bytes.Buffer
        for {
            tempOutput := make([]byte, 1024)
            n, err := stdout0.Read(tempOutput)
            if err != nil {
                if err == io.EOF {
                    break
                } else {
                    fmt.Printf("Error: Couldn't read data from the pipe: %s\n", err)
                    return ""
                }
            }
            if n > 0 {
                outputBuf0.Write(tempOutput[:n])
            }
        }
        //fmt.Printf("%s\n", outputBuf0.String())
        res := fmt.Sprintf("%v",outputBuf0.String())
        return res
    } else {
        outputBuf0 := bufio.NewReader(stdout0)
        var resBuffer bytes.Buffer

        for{
            //outputBuf0 預設帶一個4K的緩衝區,第二個引數為false表示讀取完所有的行
            output0, _, err := outputBuf0.ReadLine()

            if err != nil {
                if err == io.EOF{
                    break
                }
                fmt.Printf("Error: Couldn't read data from the pipe: %s\n", err)
                return ""
            }
            output0 = append(output0,'\n')
            resBuffer.Write(output0)
        }
        res := fmt.Sprintf("%v",resBuffer.String())
        return res
    }
}


func Command(cmds []string) *exec.Cmd {
    name:= cmds[0]
    cmd := &exec.Cmd{
        Path: name,
        Args: cmds,
    }

    if filepath.Base(name) == name {
        if lp, err := exec.LookPath(name); err != nil {
            //cmd.lookPathErr = err
            ErrorHandle(err)
        } else {
            cmd.Path = lp
        }
    }
    return cmd
}

func a11()  {
    //命令列引數不能包含空格,比如-ht 是錯的,-ht是對的
    cmd := []string{"/opt/wks/go/dbm_go/src/dbm/consistency/consis_0.6.7", "-cht",  "192.168.177.67", "-cpt", "3316", "-ht","114.67.105.113,192.168.177.67", "-pt","3306,3316", "-slot",  "-json", "-db", "vodb", "-timeStart", "2020-09-11 14:09:27", "-pl", "2"}
    res := tools.PipCmd(cmd,true)
    fmt.Println(res)
}