Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

printing stdout in realtime from a subprocess that requires stdin

Tags:

This is a follow up to this question, but if I want to pass an argument to stdin to subprocess, how can I get the output in real time? This is what I currently have; I also tried replacing Popen with call from the subprocess module and this just leads to the script hanging.

from subprocess import Popen, PIPE, STDOUT cmd = 'rsync --rsh=ssh -rv --files-from=- thisdir/ servername:folder/' p = Popen(cmd.split(), stdout=PIPE, stdin=PIPE, stderr=STDOUT) subfolders = '\n'.join(['subfolder1','subfolder2']) output = p.communicate(input=subfolders)[0] print output 

In the former question where I did not have to pass stdin I was suggested to use p.stdout.readline, there there is no room there to pipe anything to stdin.

Addendum: This works for the transfer, but I see the output only at the end and I would like to see the details of the transfer while it's happening.

like image 547
hatmatrix Avatar asked Jul 01 '13 19:07

hatmatrix


1 Answers

In order to grab stdout from the subprocess in real time you need to decide exactly what behavior you want; specifically, you need to decide whether you want to deal with the output line-by-line or character-by-character, and whether you want to block while waiting for output or be able to do something else while waiting.

It looks like it will probably suffice for your case to read the output in line-buffered fashion, blocking until each complete line comes in, which means the convenience functions provided by subprocess are good enough:

p = subprocess.Popen(some_cmd, stdout=subprocess.PIPE) # Grab stdout line by line as it becomes available.  This will loop until  # p terminates. while p.poll() is None:     l = p.stdout.readline() # This blocks until it receives a newline.     print l # When the subprocess terminates there might be unconsumed output  # that still needs to be processed. print p.stdout.read() 

If you need to write to the stdin of the process, just use another pipe:

p = subprocess.Popen(some_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) # Send input to p. p.stdin.write("some input\n") p.stdin.flush() # Now start grabbing output. while p.poll() is None:     l = p.stdout.readline()     print l print p.stdout.read() 

Pace the other answer, there's no need to indirect through a file in order to pass input to the subprocess.

like image 195
Alp Avatar answered Oct 19 '22 01:10

Alp