Go Os/exec优雅,循环兼容标准输入和标准输出

Go Os/exec优雅,循环兼容标准输入和标准输出,go,terminal,Go,Terminal,示例脚本只是“wc-m”命令的包装器,是一个简单的符号计数器。 我试图用“teststrings”片段元素来输入。并在输出侦听器goroutine处接收每个字符串的符号数。寻找一种让“wc”永远倾听输入的方法。我注意到当我增加睡眠时 time.Sleep(6000 * time.Nanosecond) 不要等待输入 package main import ( "bytes" "fmt" "os/exec" "time" ) func main() {

示例脚本只是“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

}

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

使用管道而不是字节。缓冲区:

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())
}

你想在
Cmd
上使用
StdinPipe
,而不是缓冲区,但为什么不直接在go中计数字符呢?@JimB这是一个简单的选择,我实际上使用了另一个命令。据我所知,
StdinPipe
在执行后立即退出。有没有办法在循环时保持管道打开?你说的“立即退出”是什么意思?管道是打开的,直到你把它关上。(这是一个
io.WriteCloser
)不完全是我需要的,假设输出像
13 3 4 8
,无论如何感谢您的想法。@Y01rY5Ogfl wc命令将标准输入读取到底,并写入一个计数。命令在读取标准输入时没有写入计数的选项。