Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print the realtime output of running child process in go?

Tags:

go

I have the following bash script bash_loop.shthat prints 1 to 10 and sleep 3 s in between.

#!/bin/bash
# Basic while loop
counter=1
while [ $counter -le 10 ]
do
    echo $counter
    ((counter++))
   sleep 3 
done
echo All done

Right now, I have my go code as follow:

burstingScript := "bash_loop.sh"
cmd := exec.Command("/bin/sh", burstingScript)

var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
    fmt.Println("An error has occurred..")
    log.Fatal(err)
}
fmt.Println(out.String())

However, this only print out everything after the cmd finish running after 30s, instead of print things as they become available.

So my question is that if I can print each number while the bash script is still running instead of printing everything all together after the bash script finishes execution.

P.S.1: In the real use case, I have to process the output of bash script in realtime, instead of simply printing things out to os.Stdout, so I am wondering if there's any command poll() interface or equivalence in go.

P.S.2:In the real use case, I want to detach from the child process as soon as I find interesting message. For example, after I read 3, I want my function return 3 immediately and not wait for the rest of output anymore, though I still want the child process (the bash script) itself to be up and running.

P.S.3: In python, I would do something like this

cmd = "./bash_loop.sh"
p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)

result = {}
while True:
    out = p.stdout.readline()
    if out == '' and p.poll() != None:
        break
    if out != '':
        #process(out)
        sys.stdout.write(out)
        sys.stdout.flush()

P.S.4: Now I have evolved my go snippet to follow. Will the child become a zombie if I return before the command finishes running?

burstingScript := path.Join(rootDir, "bash_loop.sh")
cmd := exec.Command("/bin/sh", burstingScript)

stdout, _ := cmd.StdoutPipe()
cmd.Start()
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
    m := scanner.Text()
    fmt.Println(m)
    //if m=="3" {
    //  return process(m)
    //}
}
cmd.Wait()
like image 245
cookieisaac Avatar asked Oct 19 '22 03:10

cookieisaac


1 Answers

Set the command output to stdout:

cmd.Stdout = os.Stdout
like image 145
JimB Avatar answered Oct 21 '22 04:10

JimB