Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading Stdout from a subprocess

Tags:

go

I am attempting to spawn a subprocess from Golang. The goal is to read and process the input line-by-line. Here is what I am trying to get working:

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

In this example, "Scanner created" is printed, but nothing happens after that.

Running this command however does result in what I am expecting to be printed to :

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

And modifying the code to directly copy to stdout works as well:

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

What am I missing that is keeping me from reading the output?

like image 795
tgrosinger Avatar asked Dec 20 '14 04:12

tgrosinger


People also ask

How do I get output to run from subprocess?

To capture the output of the subprocess. run method, use an additional argument named “capture_output=True”. You can individually access stdout and stderr values by using “output. stdout” and “output.

What is subprocess stdout?

When subprocess. STDOUT is specified, the subprocess's standard error stream will be connected to the same pipe as the standard output stream. All other keyword arguments are passed to subprocess. Popen without interpretation, except for bufsize, universal_newlines and shell, which should not be specified at all.


2 Answers

This seems to work fine, and it works with go readStuff(scanner) and also with just readStuff(scanner) - I don't think that this usage actually calls for a goroutine, but don't know the actual context.:

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

This is the junk.sh I used for testing.

#!/bin/bash
for i in `seq 1 10`;
do
  echo $i
  sleep 1
done    
like image 54
rfay Avatar answered Nov 04 '22 09:11

rfay


Seems you need not

go readStuff(scanner)

because of

cmd.Start()

do system fork itself so just

readStuff(scanner)

would be enough to my mind (not spawning gorouting for that)

like image 30
Uvelichitel Avatar answered Nov 04 '22 09:11

Uvelichitel