从子进程读取Stdout

时间:2014-12-20 04:24:48

标签: go

我正在尝试从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

我错过了什么让我无法阅读输出?

3 个答案:

答案 0 :(得分:4)

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

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

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

  3. 在确保从cmd.Wait()读取所有数据之前,不应致电stdout。结果是非确定性的(实际上,它是竞争条件)。查看有关os/exec包的文档。如果您绝对需要在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()
    

答案 1 :(得分:1)

似乎你不需要

go readStuff(scanner)

因为

cmd.Start()

做系统分叉本身 所以只是

readStuff(scanner)

对我来说已经足够了 (不是为此而产生的)

答案 2 :(得分:0)

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

&#13;
&#13;
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)
}
&#13;
&#13;
&#13;

这是我用来测试的垃圾。

&#13;
&#13;
#!/bin/bash

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