Os / exec优雅,循环兼容的stdin和stdout输入/输出

时间:2016-04-15 13:56:08

标签: go terminal

示例脚本只是" wc -m"的包装。命令,简单的符号计数器。 我尝试使用" teststrings"切片元素。并在输出监听器goroutine上接收每个字符串的符号数。寻找一种方法来制作" wc"永远听取输入。当我把睡眠增加到

时我会注意到
time.Sleep(6000 * time.Nanosecond)

不等待输入。

package main

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

func main() {
    BashCommand := exec.Command("wc", "-m")
    InputBytes := &bytes.Buffer{}
    OutputBytes := &bytes.Buffer{}
    BashCommand.Stdin = InputBytes
    BashCommand.Stdout = OutputBytes
    e := BashCommand.Start()
    time.Sleep(1 * time.Nanosecond)
    _, _ = InputBytes.Write([]byte("13symbolsting"))
    if e != nil {
        fmt.Println(e)
    }
    fmt.Println("after run")

    teststrings := []string{
        "one",
        "twoo",
        "threeeee",
    }
    for _, s := range teststrings {
        _, _ = InputBytes.Write([]byte(s))

    }

    //result printer
    go func() {
        for {
            line, _ := OutputBytes.ReadString('\n')
            if line != "" {
                fmt.Println(line)
            }
        }
    }()
    var input string
    fmt.Scanln(&input) //dont exit until keypress

}

1 个答案:

答案 0 :(得分:3)

如果将睡眠增加到一个较大的值,那么在将数据写入InputBytes之前,由InputBytes泵送进程的命令启动的goroutine会运行。 goroutine关闭了孩子的管道,并在没有读取任何数据的情况下退出。

使用管道而不是bytes.Buffer:

c := exec.Command("wc", "-m")
w, _ := c.StdinPipe()
r, _ := c.StdoutPipe()
if err := c.Start(); err != nil {
    log.Fatal(err)
}

w.Write([]byte("13symbolsting"))
teststrings := []string{
    "one",
    "twoo",
    "threeeee",
}
for _, s := range teststrings {
    w.Write([]byte(s))

}
w.Close() // Close pipe to indicate input is done.

var wg sync.WaitGroup
wg.Add(1)

go func() {
    s := bufio.NewScanner(r)
    for s.Scan() {
        fmt.Println(s.Text())
    }
    wg.Done()
}()

wg.Wait()

另一种选择是在启动命令之前写入bytes.Buffer并在读取输出之前等待命令完成:

c := exec.Command("wc", "-m")
var w, r bytes.Buffer
c.Stdin = &w
c.Stdout = &r

// Write data before starting command.

w.Write([]byte("13symbolsting"))
teststrings := []string{
    "one",
    "twoo",
    "threeeee",
}
for _, s := range teststrings {
    w.Write([]byte(s))

}

if err := c.Start(); err != nil {
    log.Fatal(err)
}

// Wait for command to complete before reading data.

if err := c.Wait(); err != nil {
    log.Fatal(err)
}

s := bufio.NewScanner(&r)
for s.Scan() {
    fmt.Println(s.Text())
}