Cannot read from Pipe using exec.Command in Go

I am writing a go program that sends data to another program via stdin and reads the response via stdout.

Here is a script which acts as an “echo server” of sorts:

import sys

if __name__=='__main__':
    for line in sys.stdin:
        print("Hello", line.strip())

When I try to communicate with this program in Go, it hangs on buf.ReadLine(). Here is my Go code:

package main

import (
    "bufio"
    "log"
    "os/exec"
)

func main() {
    cmd := exec.Command("python3", "app.py")
    stdout, _ := cmd.StdoutPipe()
    stdin, _ := cmd.StdinPipe()

    cmd.Start()

    stdin.Write([]byte("Bob\n"))

    buf := bufio.NewReader(stdout)
    buf.ReadLine()
    log.Println(buf)
}

The Write() function does not return an error. However, the program hangs when I try to ReadLine(). What am I doing wrong?

  • 1

    buf.ReadLine() returns values which you are ignoring (along with ignoring other errors). You want to print the line returned by buf.ReadLine, not buf. Also note the documentation which states: “Most callers should use ReadBytes(‘\n’) or ReadString(‘\n’) instead or use a Scanner.”. This is unrelated to the python output buffering which is causing the program to hang.

    – 




It’s not a problem with the Go code; your Python program is buffering output because its stdout is a pipe rather than a terminal, so Go has nothing to read, and you have a deadlock where both processes are waiting for input, and neither one produces any output.

See how can I flush the output of the print function or Disable output buffering for ways to deal with it in Python — the first one works for a single print statement, and the second one for the whole program. For your simple example they’re both the same, but in other cases they may not be so it’s worth understanding the options.

Leave a Comment