I'm trying to read stdout from a long-running (blocking / shell-like) command with the ultimate goal of creating a sidecar process that Go can interact with.
I have the following MCVE:
func main() {
var err error
// Build the long-running command
args := []string{"-i0", "-o0", "-e0", "/usr/local/bin/ipython"}
cmd := exec.Command("stdbuf", args...)
// Keep the stdin file descriptor open
// Spawned command should block waiting for input
_, err = cmd.StdinPipe()
if err != nil {
panic(err)
}
// Setup pipe of `Reader` type
var stdoutBuf []byte
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
// Start the command
if err = cmd.Start(); err != nil {
panic(err)
}
go func() {
for {
// Asynchronously continue reading from stdout
n, err := stdout.Read(stdoutBuf)
fmt.Println(n)
if err != nil {
panic(err)
}
fmt.Println(stdoutBuf)
time.Sleep(time.Millisecond * 2000)
}
}()
// Block forever
if err = cmd.Wait(); err != nil {
panic(err)
}
}
Semantically this approach seems like it would work. I would expect that stdout.Read
would return something (ipython
shell preamble), but n
is always 0.
Reader.Read
in this example never read anything?StdoutPipe
if there is nothing to be read?I don't think anything is wrong with the process itself (which would cause an invalid file descriptor read) because Start
doesn't panic
and it seem like cmd.Wait
blocks forever.
Why does
Reader.Read
in this example never read anything?
Because you are reading into a buffer of size 0, which is what var stdoutBuf []byte
creates. Instead, use something like:
stdoutBuf := make([]byte, 4096)
You may also want to use bufio
.
Somewhat related question: is there a way I can block on reading
StdoutPipe
if there is nothing to be read?
stdout.Read
already blocks, as is typical (though not required) for an io.Reader
:
If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more. [...] Implementations of Read are discouraged from returning a zero byte count with a nil error, except when len(p) == 0.