Reputation: 13
I've noticed that the "&>" operator within a subprocess.Popen() call immediately provides a return code, even in scenarios where it intuitively shouldn't be. To illustrate:
>>> import subprocess
>>> a = subprocess.Popen("sleep 5 > a.txt", shell = True)
>>> print(a.poll()) # immediately try printing
None
>>> print(a.poll()) # wait 5 seconds
0
>>> a = subprocess.Popen("sleep 5 &> a.txt", shell = True)
>>> print(a.poll()) # immediately try printing
0
>>> a = subprocess.Popen("sleep 5 > a.txt 2>&1", shell = True) # this should be the same as using &>
>>> print(a.poll()) # immediately try printing
None
>>> print(a.poll()) # wait 5 seconds
0
I'm running this on Python 3.5.2. My machine runs bash by default.
Does anyone know why subprocess isn't supporting the correct "&>" behavior here?
Upvotes: 1
Views: 99
Reputation: 531155
Your default login shell is bash
. subprocess.Popen
, though, uses the system default shell /bin/sh
, which does not recognize the &>
operator. If you want to force it to use bash
, use the executable
option:
a = subprocess.Popen("sleep 5 &> a.txt", shell=True, executable="/bin/bash")
Alternatively, you can handle the redirection yourself in Python:
with open("a.txt", "w") as fh:
a = subprocess.Popen(["sleep", "5"], stdout=fh, stderr=fh)
Upvotes: 2
Reputation: 18697
That's because &>
is a bashism, and Popen
by default uses /bin/sh
when shell=True
.
From the subprocess.Popen
docs:
The
executable
argument specifies a replacement program to execute. It is very seldom needed. Whenshell=False
, executable replaces the program to execute specified by args. However, the original args is still passed to the program. Most programs treat the program specified by args as the command name, which can then be different from the program actually executed. On POSIX, the args name becomes the display name for the executable in utilities such as ps. Ifshell=True
, on POSIX theexecutable
argument specifies a replacement shell for the default/bin/sh
.
The fix is to specify the executable
parameter explicitly, like:
subprocess.Popen("sleep 5 &> a.txt", shell=True, executable='/bin/bash')
Upvotes: 2