从子流程读取标准输出



我正在尝试从Golang生成一个子进程。目标是逐行读取和处理输入。这是我正在努力工作的内容:

func readStuff(scanner *bufio.Scanner) {
    for scanner.Scan() {
        fmt.Println("Performed Scan")
        fmt.Println(scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, "reading standard input:", err)
    }
}
func main() {
    cmd := exec.Command("/usr/local/bin/pocketsphinx_continuous", "-inmic", "yes")
    out, err := cmd.StdoutPipe()
    err = cmd.Start()
    checkError(err)
    scanner := bufio.NewScanner(out)
    fmt.Println("Scanner created")
    defer cmd.Wait()
    go readStuff(scanner)
}

在此示例中,打印了"已创建扫描仪",但之后没有任何反应。

但是运行此命令确实会导致我期望打印到:

/usr/local/bin/pocketsphinx_continuous -inmic yes 1>out.txt

修改代码以直接复制到stdout也可以:

cmd := exec.Command("/usr/local/bin/pocketsphinx_continuous", "-inmic", "yes")
cmd.Stdout = os.Stdout

错过了什么阻止我阅读输出?

您可能需要检查多项内容。

  1. 不检查 cmd.StdoutPipe() 返回的错误代码。应该是。

  2. pocketsphinx_continuous 命令需要提供-hmm-dict参数。否则,它将失败,并且所有输出实际上都发送到stderr而不是stdout。在这里,你只读stdout,但没有什么可读的。

  3. 在确保已从stdout读取所有数据之前,不应调用cmd.Wait()。结果是不确定的(实际上,这是一个竞争条件(。查看有关os/exec包的文档。如果你绝对需要在 goroutines 中完成解析,你需要在调用 goroutine cmd.Wait() 之前与 goroutine 的末尾同步。例如,您可以将函数编写为:

    func readStuff(scanner *bufio.Scanner, stop chan bool) {
        // Scanning code
        // ...
        stop<-true
    }
    

    主代码为:

    stop := make(chan bool)
    go readStuff(scanner,stop)
    <-stop
    cmd.Wait()
    

似乎你不需要

go readStuff(scanner)

cmd.Start()

做系统分叉本身所以只是

readStuff(scanner)

就足够了(不是为此生成 goroute(

这似乎工作正常,它适用于go readStuff(scanner),也适用于readStuff(scanner) - 我不认为这种用法实际上需要一个goroutine,但不知道实际的上下文。

package main
import (
    "bufio"
    "fmt"
    "os"
    "os/exec"
)
func readStuff(scanner *bufio.Scanner) {
    for scanner.Scan() {
        fmt.Println("Performed Scan")
        fmt.Println(scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, "reading standard input:", err)
    }
}
func main() {
    cmd := exec.Command("/Users/rfay/bin/junk.sh")
    out, err := cmd.StdoutPipe()
    err = cmd.Start()
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to start err=%v", err)
        os.Exit(1)
    }
    scanner := bufio.NewScanner(out)
    fmt.Println("Scanner created")
    defer cmd.Wait()
    go readStuff(scanner)
}

这是我用于测试 junk.sh。

#!/bin/bash
for i in `seq 1 10`;
do
  echo $i
  sleep 1
done    

最新更新