为什么 args 是序列时 subprocess.Popen 不工作?

8 投票
3 回答
13028 浏览
提问于 2025-04-15 20:09

我在使用subprocess.Popen的时候遇到了问题,特别是当给args参数传递一个序列时。

举个例子:

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

这个是可以正常工作的(它会打印出/home/support/Maildir目录的正确大小):

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

到底哪里出了问题呢?

3 个回答

1

应该是 ["du", "-s", "-b", maildir]

5

根据文档

在Unix系统中,当使用shell=True时:如果args是一个字符串,那么它就是要通过命令行执行的命令字符串。如果args是一个序列(比如列表),那么第一个项目就是命令字符串,后面的项目会被当作额外的命令参数。

所以,可以尝试

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

或者

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

来自文档

在Unix系统中,当设置为shell=True时:[…] 如果args是一个序列,第一个项目指定了命令字符串,任何额外的项目会被当作额外的参数传给shell本身。也就是说,Popen的作用相当于:

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

在你的情况下,这意味着:

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

这表示 -s-bmaildir 是被shell当作选项来理解的,而不是被 du 理解(你可以在命令行试试!)。

因为在你的情况下其实不需要 shell=True,所以你可以直接把它去掉:

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

另外,你也可以继续使用你原来的方法,但那样的话就不需要用列表。你还需要注意目录名中的空格:

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

撰写回答