Python:subprocess调用时shell=False无效

17 投票
4 回答
28421 浏览
提问于 2025-04-18 18:18

我正在用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 个回答

0

不要直接使用文件名的目录,而是在前面加上 python 这个词,前提是你已经把 Python 的路径添加到了你的环境变量里。如果你不确定是否添加了,可以重新运行 Python 的安装程序,只要你有一个新的 Python 版本就可以了。

我说的意思是:

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

除了Enrico.bacis的回答,还有两种方式可以调用程序。使用 shell=True 时,你需要给出一个完整的命令字符串。而使用 shell=False 时,你需要提供一个列表。

如果你要使用一些特殊的命令,比如 *.jpg 或者 2> /dev/null,就用 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
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

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 教程

撰写回答