8

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?

mvladic
  • 1,179
  • 2
  • 12
  • 15
  • See also: http://stackoverflow.com/questions/1818774/python-subprocess/1818902#1818902 – codeape Mar 08 '10 at 11:37
  • 1
    "doesn't work" is not a useful error description! –  Mar 08 '10 at 11:52
  • 1
    @hop: your comment doesn't say why it wasn't useful. @pero: You could improve the question by including the output you get when you execute the commands. Showing the expected output and the output you got allows us to know if we're seeing what you saw when we try to replicate your issue. (Of course since you got an answer then there must have been enough info in the question.) – Mnebuerquo Sep 17 '10 at 02:52

3 Answers3

12

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]
5

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], ...
YOU
  • 120,166
  • 34
  • 186
  • 219
  • 1
    Thanks. Sequence ["du", "-s", "-b", maildir] works if I remove shell=True, which is not needed anyway. – mvladic Mar 08 '10 at 11:57
  • the relevant point is that additional items are treated as _shell arguments_, not arguments to du –  Mar 08 '10 at 14:29
1

it should be ["du", "-s", "-b", maildir]

SilentGhost
  • 307,395
  • 66
  • 306
  • 293