关于python:subprocess.Popen给出随机结果

subprocess.Popen gives random result

我写了一段简单的代码:

1
2
3
import subprocess
p=subprocess.Popen('mkdir -p ./{a,b,c}', shell=True, stderr=subprocess.STDOUT)
p.wait()

不幸的是,它并不总是如我所料。也就是说,当我在PC上运行它时,一切都正常(ls-l给了我三个dirs:a、b和c)。但是当我的同事在他的桌面上运行它时,他会…一个名为"A、B、C"的目录。我们都使用python 2.7.3。为什么会这样?你将如何修复它?

我试图自己找到答案。根据手册:"args应该是程序参数序列,或者是单个字符串。默认情况下,如果args是序列,则要执行的程序是args中的第一个项。如果args是字符串,则解释取决于平台,如下所述。有关与默认行为的其他差异,请参阅shell和可执行参数。除非另有说明,建议按顺序传递参数。"

所以我尝试在shell中执行代码:

1
python -c"import subprocess; p=subprocess.Popen(['mkdir', '-p', './{ea,fa,ga}'], shell=True, stderr=subprocess.STDOUT); p.wait()"

我得到了:

1
mkdir: missing operand

我会感谢你的任何建议

谢谢!


./{a,b,c}语法是bash语法,并非所有shell都支持。

文件上说:

On Unix with shell=True, the shell defaults to /bin/sh. If args is a
string, the string specifies the command to execute through the shell.

因此,只有当/bin/sh与支持该语法的shell(如bashzsh进行符号链接时,您的命令才有效。您的同事可能正在使用dash或其他不支持此功能的shell。

您不应该依赖于用户的默认shell。相反,使用完全扩展编写完整命令:

1
p = subprocess.Popen('mkdir -p ./a ./b ./c', shell=True, stderr=subprocess.STDOUT)

谢谢大家的回答。似乎最好的方法就是简单地使用/bin/sh语法。我将代码更改为使用:

1
'mkdir -p ./a ./b ./c'

如你所建议的。

我避免使用mkdir()函数,因为我正在编写一个包含大量系统调用的脚本,并且我希望提供优雅的--dry-run选项(这样我可以列出所有命令)。

问题解决了-谢谢!


这里有几个问题。

  • 首先:如果您使用的是一系列参数,请不要设置"shell=true"(这在popen手册中是推荐的)。将其设置为false,您将看到mkdir命令将被接受。
  • "/a,b,c"是bash中的特定语法。如果你的同事使用了不同的外壳,它可能不会工作,也不会表现得不同。
  • 您应该使用python"mkdir"命令,而不是调用shell命令,无论服务器/shell/OS是什么,它都可以工作。

据我所知,mkdir(path,[mode])方法在处理多平台项目时更安全。

1
os.mkdir(os.getcwd()/a)

然而,它不如采用子流程方法那么优雅。