Почему subprocess.Popen не работает, когда args является последовательностью?

У меня проблема с subprocess.Popen, когда параметр args задан как последовательность.

Например:

import subprocess
maildir = "/home/support/Maildir"

Это работает (он печатает правильный размер /home/support/Maildir dir):

size = subprocess.Popen(["du -s -b " + maildir], shell=True,
                        stdout=subprocess.PIPE).communicate()[0].split()[0]
print size

Но это не работает (попробуйте):

size = subprocess.Popen(["du", "-s -b", maildir], shell=True,
                        stdout=subprocess.PIPE).communicate()[0].split()[0]
print size

Что не так?

Ответы

Ответ 1

Из документации

В Unix с оболочкой = True: [...] Если args - это последовательность, первый элемент указывает командной строки, и любые дополнительные элементы будут рассматриваться как дополнительные аргументы сама оболочка. То есть, Popen делает эквивалент:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

Что переводит в вашем случае:

Popen(['/bin/sh', '-c', 'du', '-s', '-b', maildir])

Это означает, что -s, -b и maildir интерпретируются как параметры оболочки, а не du (попробуйте в командной строке оболочки!).

Так как shell=True в любом случае не требуется в вашем случае, вы можете просто удалить его:

size = subprocess.Popen(['du', '-s', '-b', maildir],
                    stdout=subprocess.PIPE).communicate()[0].split()[0]

В качестве альтернативы вы можете просто использовать свой подход orignal, но в этом случае вам не нужен список. Вам также нужно будет позаботиться о пробелах в названии каталога:

size = subprocess.Popen('du -s -b "%s"' % maildir, shell=True,
                    stdout=subprocess.PIPE).communicate()[0].split()[0]

Ответ 2

Из document,

В Unix с shell = True: если args является строка, она указывает команду строка для выполнения через оболочку. Если args является последовательностью, первый элемент задает командную строку, а дополнительные предметы будут рассматриваться как дополнительные аргументы оболочки.

Итак, Try

subprocess.Popen("du -s -b " + maildir, ...

или

subprocess.Popen(["du","-s","-b",maildir], ...

Ответ 3

он должен быть ["du", "-s", "-b", maildir]