I'm trying to launch an 'rsync' using subprocess module and Popen inside of a thread. After I call the rsync I need to read the output as well. I'm using the communicate method to read the output. The code runs fine when I do not use a thread. It appears that when I use a thread it hangs on the communicate call. Another thing I've noticed is that when I set shell=False I get nothing back from the communicate when running in a thread.
Asked
Active
Viewed 8.3k times
2 Answers
47
You didn't supply any code for us to look at, but here's a sample that does something similar to what you describe:
import threading
import subprocess
class MyClass(threading.Thread):
def __init__(self):
self.stdout = None
self.stderr = None
threading.Thread.__init__(self)
def run(self):
p = subprocess.Popen('rsync -av /etc/passwd /tmp'.split(),
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.stdout, self.stderr = p.communicate()
myclass = MyClass()
myclass.start()
myclass.join()
print myclass.stdout

Ryan Bright
- 3,495
- 21
- 20
-
Yes that is pretty much exactly what I am doing. I'd like to be read the output inside the thread though. I should also note I'm using Python 2.3. I've grabbed a copy of subprocess from 2.4. – noahd Jun 12 '09 at 04:55
-
I should be more clear that is what I am doing but it doesn't work. In this case the communicate call will not return anything and the command does not appear to execute. If I set shell=True the communicate hangs the thread. Then after I stop the python I end up with a defunct ssh process. – noahd Jun 12 '09 at 12:49
-
1I tested the sample code provided and I get the same behavior. I tried substituting a different command like 'ls -la' and I had no issues so I think it has something to do with rsync or maybe this version of python. – noahd Jun 12 '09 at 18:20
-
1Got this to work. There was something wrong with my environment. Thanks for your help! – noahd Jun 12 '09 at 18:44
-
21Just curious as to what it was that you did to correct your issue? I'm in a similar position that I have a subprocess that I'm running in a thread, from which I would like to capture output as it's executing. The only time the 'communicate()' or 'stdout.readlines()' calls return any output is once the applications has completely terminated. If I pull the same code out of the thread, it works just fine. – Jason Mock Jul 11 '11 at 23:18
-
Just off the cuff, I wonder if there were buffers that weren't getting flushed quickly enough. – Jon Coombs Dec 02 '14 at 21:03
-
`'rsync -av /etc/passwd /tmp'.split()` is smart , I was `["rsync", "-av", "/etc/passwd", "/tmp"]` doing this way – alper Aug 07 '21 at 23:00
-
I have the same problem (happens on my Macbook but not Arch Linux), and get reminded of [this](https://xkcd.com/979/). – DUO Labs May 16 '22 at 23:31
-
For anyone coming for Google, my problem was that I used a `signal.pause()` right after the thread. Changing it to `threading.Event().wait()` fixed the problem. – DUO Labs May 17 '22 at 14:18
18
Here's a great implementation not using threads: constantly-print-subprocess-output-while-process-is-running
import subprocess
def execute(command):
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = ''
# Poll process for new output until finished
for line in iter(process.stdout.readline, ""):
print line,
output += line
process.wait()
exitCode = process.returncode
if (exitCode == 0):
return output
else:
raise Exception(command, exitCode, output)
execute(['ping', 'localhost'])
-
9It should be noted that this implementation will block on `process.stdout.readline()`. – Ian Oct 17 '13 at 01:58
-
Also note that adding `universal_newlines=True` to the `Popen` command is useful if the process has a loading bar, and is repeatedly printing the progress followed by `\r`. Without the `universal_newlines` option you would need to wait until the final `\n` before getting one giant string (that contains all of the progress bars concatenated together). – Aaron Voelker Mar 03 '20 at 17:59