Why subprocess.Popen doesn't work when args is sequence?
I'm having a problem with subprocess.Popen when args parameter is given as sequence.
For example:
import subprocess
maildir = "/home/support/Maildir"
This works (it prints the correct size of /home/support/Maildir dir):
size = subprocess.Popen(["du -s -b " + maildir], shell=True,
stdout=subprocess.PIPE).communicate()[0].split()[0]
print size
But, this doesn't work (try it):
size = subprocess.Popen(["du", "-s -b", maildir], shell=True,
stdout=subprocess.PIPE).communicate()[0].split()[0]
print size
What's wrong?
Solution 1:
From the documentation
On Unix, with shell=True: […] If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself. That is to say, Popen does the equivalent of:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
Which translates in your case to:
Popen(['/bin/sh', '-c', 'du', '-s', '-b', maildir])
This means that -s
, -b
and maildir
are interpreted as options by the shell, not by du
(try it on the shell commandline!).
Since shell=True
is not needed in your case anyway, you could just remove it:
size = subprocess.Popen(['du', '-s', '-b', maildir],
stdout=subprocess.PIPE).communicate()[0].split()[0]
Alternatively you could just use your orignal approach, but you don't need a list in that case. You would also have to take care of spaces in the directory name:
size = subprocess.Popen('du -s -b "%s"' % maildir, shell=True,
stdout=subprocess.PIPE).communicate()[0].split()[0]
Solution 2:
From document,
On Unix, with shell=True: If args is a string, it specifies the command string to execute through the shell. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional shell arguments.
So, Try
subprocess.Popen("du -s -b " + maildir, ...
or
subprocess.Popen(["du","-s","-b",maildir], ...
Solution 3:
it should be ["du", "-s", "-b", maildir]