这里的其他答案充分说明了安全警告,subprocess
文档中也提到了这些警告。但是除此之外,启动外壳程序以启动要运行的程序的开销通常是不必要的,对于您实际上没有使用任何外壳程序功能的情况而言,这绝对是愚蠢的。而且,额外的隐藏复杂性会让您感到恐惧,特别是如果您对外壳程序或它提供的服务不是很熟悉的话。
在与shell的交互非常简单的地方,您现在需要Python脚本的阅读者和维护者(可能是您将来的自己,也可能不是您将来的自己)来理解Python和shell脚本。记住Python的座右铭“明确胜于隐含”。即使Python代码比等效的(并且通常非常简洁)shell脚本要复杂一些,您最好还是删除外壳并用本机Python构造替换功能。尽量减少在外部过程中完成的工作并尽可能地将控制保持在自己的代码中通常是一个好主意,这仅仅是因为它可以提高可见性并减少副作用(有害的或有害的)的风险。
通配符扩展,变量插值和重定向都很容易用本机Python构造替换。复杂的Shell管道(其中的部分或全部无法用Python合理地重写)可能是您可以考虑使用Shell的一种情况。您仍然应该确保您了解性能和安全性含义。
在平凡的情况下,要避免shell=True
,只需替换
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
与
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
请注意,第一个参数如何是要传递给的字符串列表execvp()
,以及通常如何不需要引用字符串和使用反斜杠的shell元字符(或有用或正确)。也许还会看到何时将引号括在shell变量周围?
顺便说一句,您经常会想避免Popen
包装中的一个较简单的包装subprocess
程序满足您的要求。如果您的Python版本足够新,则应该使用subprocess.run
。
- 随着
check=True
如果命令你运行失败就会失败。
- 有了
stdout=subprocess.PIPE
这将捕获命令的输出。
- 有点晦涩难懂,
universal_newlines=True
它将输出解码为正确的Unicode字符串(bytes
否则,在Python 3中只是在系统编码中)。
如果不是这样,则对于许多任务,您希望check_output
从命令获取输出,同时检查命令是否成功,或者check_call
是否没有要收集的输出。
最后,我引用大卫·科恩(David Korn)的话说:“编写可移植的shell比移植可移植的shell脚本容易。” 甚至subprocess.run('echo "$HOME"', shell=True)
不能移植到Windows。
-l
如果传递给/bin/sh
(shell)而不是Unix上的ls
程序。在大多数情况下,应使用字符串参数而不是列表。shell=True
shell=True