subprocess中'shell=True'的实际意义
我正在使用 subprocess
模块来调用不同的进程。不过,我有一个问题。
在下面的代码中:
callProcess = subprocess.Popen(['ls', '-l'], shell=True)
还有
callProcess = subprocess.Popen(['ls', '-l']) # without shell
这两种方式都能正常工作。看完文档后,我了解到 shell=True
的意思是通过命令行来执行代码。这意味着如果不加这个选项,进程就是直接启动的。
那么在我的情况下,我应该选择哪种方式呢?我需要运行一个进程并获取它的输出。通过命令行调用和直接调用有什么好处呢?
7 个回答
这里有一个例子,说明使用Shell=True时可能会出问题。
>>> 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 / # THIS WILL DELETE EVERYTHING IN ROOT PARTITION!!!
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...
你可以查看这个文档了解更多信息:subprocess.call()
>>> import subprocess >>> subprocess.call('echo $HOME') Traceback (most recent call last): ... OSError: [Errno 2] No such file or directory >>> >>> subprocess.call('echo $HOME', shell=True) /user/khong 0
把shell参数设置为一个真实的值,会让子进程启动一个中间的shell进程,并告诉它去执行这个命令。换句话说,使用中间的shell意味着在执行命令之前,命令字符串里的变量、通配符和其他特殊的shell功能都会被处理。在这个例子中,$HOME在执行echo命令之前就已经被处理了。实际上,这就是命令有shell扩展的情况,而命令ls -l则被认为是一个简单的命令。
不通过命令行调用的好处是,你不会启动一个“神秘程序”。在POSIX系统中,环境变量SHELL
决定了哪个程序被当作“命令行”来运行。在Windows系统中,没有类似的程序,只有cmd.exe。
所以,通过命令行调用会启动用户选择的程序,并且这个选择依赖于操作系统。一般来说,最好避免通过命令行来调用程序。
不过,通过命令行调用可以让你使用环境变量和文件通配符,这些都是命令行的常规功能。在POSIX系统中,命令行会把文件通配符扩展成文件列表。在Windows中,文件通配符(比如“*.*”)不会被命令行扩展,但在命令行中,环境变量是会被cmd.exe扩展的。
如果你觉得需要环境变量扩展和文件通配符,建议你了解一下1992年左右的ILS
攻击,这些攻击是针对通过命令行调用子程序的网络服务的。比如,涉及ILS
的各种sendmail
后门。
总之,建议使用shell=False
。