Python:使用shell=False的子进程调用无法工作

17

我正在使用Python脚本来调用Java虚拟机。以下命令有效:

subprocess.call(["./rvm"], shell=False)  # works
subprocess.call(["./rvm xyz"], shell=True) # works

但是,

subprocess.call(["./rvm xyz"], shell=False) # not working

无法正常工作。 Python文档建议避免使用shell=True

4个回答

36

您需要将命令拆分为单独的字符串:

subprocess.call(["./rvm", "xyz"], shell=False)

shell=True时,字符串可以使用,但是当shell=False时,你需要使用参数列表。

shlex模块对于处理更复杂的命令和输入很有用,值得学习。

import shlex

cmd = "python  foo.py"
subprocess.call(shlex.split(cmd), shell=False)

shlex tut


这个答案也解决了我的问题。你能详细说明一下为什么在shell=False时需要参数列表而在shell=True时字符串就可以工作吗?我听说当有输入时,shell=True非常危险,所以我试图避免使用它。 - Tommy
2
@Tommy,通常情况下应避免使用shell=True,如果您完全控制正在运行的内容,则使用它并不是世界末日,但几乎可以使用shell=False完成使用shell=True的所有操作。当您传递参数列表时,至少在Unix上,第一个参数是要执行的命令,其余是该命令的参数,如果您使用shell=True,则必须像将其传递给shell一样精确地传递命令。以下是shell=True可能允许的示例:https://docs.python.org/2/library/subprocess.html#frequently-used-arguments - Padraic Cunningham
1
我认为这是一个奇怪的API,因为它的结构会根据另一个布尔参数(是否为Shell=True)而改变一个参数的结构(这里是arg列表或命令)。这应该在subprocess内部处理,以便无论shell如何,都传递相同的参数。 - Tommy

8
如果你想使用shell=True,这是合法的,否则它将从标准库中删除。文档并没有建议避免使用它,而是说道

执行包含未经过滤的来自不受信任来源的输入的 shell 命令会使程序易受 shell 注入攻击,这是一个严重的安全漏洞,可能导致任意命令执行。因此,在命令字符串由外部输入构建的情况下,强烈不建议使用shell=True

但在你的情况下,你不是从用户输入构建命令,你的命令是固定的,所以你的代码不会出现 shell 注入 问题。你可以控制 shell 将要执行的内容,如果你的代码本身不恶意,那么就是安全的。

shell 注入示例

为了解释为什么 shell 注入如此糟糕,这是文档中使用的示例:
>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / #
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...

编辑

根据您提供的额外信息,编辑问题时,请遵循Padraic的答案。只有在必要时才应使用shell=True


4
除了Enrico.bacis的答案,还有两种调用程序的方式。使用shell=True,给它一个完整的命令字符串;使用shell=False,给它一个列表。
如果您使用诸如*.jpg2> /dev/null之类的shell技巧,请使用shell=True; 但一般情况下我建议使用shell=False--正如Enrico所说,这样更耐用。

来源

import subprocess
subprocess.check_call(['/bin/echo', 'beer'], shell=False)
subprocess.check_call('/bin/echo beer', shell=True)

输出

beer
beer

0

不要使用文件名目录,而是在其前面添加单词python,前提是您已将Python路径添加到环境变量中。如果您不确定,可以重新运行Python安装程序,前提是您有新版本的Python。

这就是我的意思:

import subprocess
subprocess.Popen('python "C:/Path/To/File/Here.py"')

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