Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go subprocess communication

GO: Is there some way to communicate with a subprocess (shell script / python script), which is waiting for input on stdin?

e.g. python script (subprocess)

import sys
while True:
    sys.stdout.write('%s\n'%eval(sys.stdin.readline()))

In the go program, I want to create a subprocess of this python script and provide it input on its stdin, whenever necessary and repeatedly, and take its output. Writing on stdout of Go program or reading/writing from a file will also do.

This is roughly what I am trying, but nothing happens -

c := exec.Command("python", "-u add.py")
si,_ := c.StdinPipe()
so,_ := c.StdoutPipe()    
c.Start()
si.Write([]byte("2+2\n")
like image 366
Palash Kumar Avatar asked Mar 27 '14 06:03

Palash Kumar


People also ask

What is the difference between subprocess call and Popen?

Popen is more general than subprocess. call . Popen doesn't block, allowing you to interact with the process while it's running, or continue with other things in your Python program. The call to Popen returns a Popen object.

How do I get output from Popen?

popen. To run a process and read all of its output, set the stdout value to PIPE and call communicate(). The above script will wait for the process to complete and then it will display the output.

Does Popen block?

Popen is nonblocking. call and check_call are blocking. You can make the Popen instance block by calling its wait or communicate method.

What does subprocess Popen return?

Popen Function The function should return a pointer to a stream that may be used to read from or write to the pipe while also creating a pipe between the calling application and the executed command. Immediately after starting, the Popen function returns data, and it does not wait for the subprocess to finish.


1 Answers

Here is a working version of your go code (python code is unchanged).

Note: checking of all errors, fixed -u flag, use of bufio to read a line, and Wait to wait for end of process.

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

func main() {
    c := exec.Command("python", "-u", "add.py")
    si, err := c.StdinPipe()
    if err != nil {
        log.Fatal(err)
    }

    so, err := c.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }
    reader := bufio.NewReader(so)

    err = c.Start()
    if err != nil {
        log.Fatal(err)
    }

    // Now do some maths
    for i := 0; i < 10; i++ {
        sum := fmt.Sprintf("2+%d\n", i)
        _, err = si.Write([]byte(sum))
        if err != nil {
            log.Fatal(err)
        }
        answer, err := reader.ReadString('\n')
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("Answer to %q is %q\n", sum, answer)
    }

    // Close the input and wait for exit
    si.Close()
    so.Close()
    c.Wait()
}

Which produces

Answer to "2+0\n" is "2\n"
Answer to "2+1\n" is "3\n"
Answer to "2+2\n" is "4\n"
Answer to "2+3\n" is "5\n"
Answer to "2+4\n" is "6\n"
Answer to "2+5\n" is "7\n"
Answer to "2+6\n" is "8\n"
Answer to "2+7\n" is "9\n"
Answer to "2+8\n" is "10\n"
Answer to "2+9\n" is "11\n"
like image 61
Nick Craig-Wood Avatar answered Oct 06 '22 14:10

Nick Craig-Wood