为什么当参数为序列时,subprocess.Popen无法工作?

8

我在使用subprocess.Popen时遇到了问题,当参数以序列的形式给出时。

例如:

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

有什么问题吗?


参见:https://dev59.com/cHI-5IYBdhLWcg3whImk#1818902 - codeape
1
“不起作用”并不是一个有用的错误描述! - user3850
1
@hop:你的评论没有说明为什么它不有用。 @pero:你可以通过包括执行命令时获得的输出来改进问题。显示期望的输出和您获得的输出允许我们知道当我们尝试复制您的问题时是否看到了您所看到的内容。(当然,既然你得到了答案,那么问题中必须有足够的信息。) - Mnebuerquo
3个回答

12

来自于文档

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], ...])

在您的情况下,这将被翻译为:

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

这意味着在shell中,-s-bmaildir 被解释为选项,而不是被du解释(在shell命令行上试一下!)。

既然在你的情况下不需要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]

5

来自文档

在Unix上,使用shell=True:如果args是一个字符串,则它指定了通过shell执行的命令字符串。 如果args是一个序列,第一项指定命令字符串,任何其他项将被视为附加的shell参数。

因此,尝试:

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

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

1
谢谢。如果我删除shell=True的话,序列["du", "-s", "-b", maildir]就能工作,而且这也是不必要的。 - mvladic
重要的是,额外的项目被视为“shell参数”,而不是du命令的参数。 - user3850

1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接