这里的其他答案充分解释了子流程文档中也提到的安全警告。但是除此之外,启动一个shell来启动你想要运行的程序的开销通常是不必要的,而且对于你实际上不使用任何shell功能的情况来说是愚蠢的。此外,额外隐藏的复杂性会吓到您,特别是如果您不太熟悉shell或它提供的服务的话。
Where the interactions with the shell are nontrivial, you now require the reader and maintainer of the Python script (which may or may not be your future self) to understand both Python and shell script. Remember the Python motto "explicit is better than implicit"; even when the Python code is going to be somewhat more complex than the equivalent (and often very terse) shell script, you might be better off removing the shell and replacing the functionality with native Python constructs. Minimizing the work done in an external process and keeping control within your own code as far as possible is often a good idea simply because it improves visibility and reduces the risks of -- wanted or unwanted -- side effects.
通配符展开、变量插值和重定向都很容易用原生Python结构替换。对于部分或全部无法用Python合理重写的复杂shell管道,也许可以考虑使用shell。您仍然应该确保了解性能和安全影响。
在简单的情况下,为了避免shell=True,只需替换即可
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
with
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
请注意,第一个参数是要传递给execvp()的字符串列表,而引用字符串和反斜杠转义shell元字符通常是不必要的(或有用或正确的)。
也许还参见何时将引号围绕一个壳变量?
如果您不想自己解决这个问题,shlex.split()函数可以帮您解决这个问题。它是Python标准库的一部分,但是当然,如果您的shell命令字符串是静态的,您可以在开发期间只运行一次,并将结果粘贴到脚本中。
顺便说一句,如果子流程包中的一个更简单的包装器满足了您的要求,那么您通常希望避免使用Popen。如果你有足够最新的Python,你可能应该使用subprocess.run。
使用check=True,如果您运行的命令失败,它将失败。
stdout =子流程。PIPE它将捕获命令的输出。
使用text=True(或者有点晦涩,使用同义词universal_newlines=True),它将输出解码为正确的Unicode字符串(在Python 3上,它只是系统编码中的字节)。
如果没有,对于许多任务,您需要check_output从命令获取输出,同时检查它是否成功,或者check_call如果没有要收集的输出。
我将引用David Korn的一句话作为结束:“编写一个可移植的shell比编写可移植的shell脚本更容易。”甚至subprocess.run('echo "$HOME"', shell=True)也不能移植到Windows。