为啥 shell=True 和 shell=False 做同样的事情? [复制]
Posted
技术标签:
【中文标题】为啥 shell=True 和 shell=False 做同样的事情? [复制]【英文标题】:Why does shell=True do the same thing as shell=False? [duplicate]为什么 shell=True 和 shell=False 做同样的事情? [复制] 【发布时间】:2019-12-30 18:18:59 【问题描述】:所以,我是编程新手(在 Linux 上学习 Python),对此知之甚少,但我认为有时尝试一些不同于讲师所说/所做的事情是件好事。但不幸的是,我期望发生的事情并没有发生。
所以,讲师告诉我输入以下内容:
subprocess.call("ifconfig", shell=True)
。
每当我运行此命令时,它都会给我我的 eth0 等...
所以我想知道如果将变量“shell”设置为“False”会发生什么,所以我尝试了这个:
subprocess.call("ifconfig", shell=False)
.
这仍然有效,每当我运行程序时,即使我将变量更改为“False”,它仍然会执行命令“ifconfig”。
为什么它一直执行这个?
【问题讨论】:
为什么不呢?请阅读the docs @ForceBru 你链接的文档部分只列出了shell
参数,它没有说明它的功能。
@Arne,我找不到直接链接到“常用参数”部分的方法,所以我给了call
函数的链接。不过,也应该阅读模块本身的文档
应该,但老实说,subprocess
文档相当混乱。如果不是这样,我们就不会收到很多关于其中内容的问题,而这些问题原则上可以通过阅读它们来解决。
【参考方案1】:
shell=True 和 shell=False 之间的一个区别是您将两个参数传递给 subprocess.call 函数。 例如:
subprocess.call("ls -l", shell=False)
# raises OSError
subprocess.call("ls -l", shell=True)
# returns the directories and files in long format
引用this链接
args 是所有调用所必需的,它应该是一个字符串,或一系列程序参数。提供一系列参数通常是首选,因为它允许模块处理任何所需的参数转义和引用(例如,允许文件名中的空格)。如果传递单个字符串,shell 必须为 True(见下文),否则字符串必须简单地命名要执行的程序而不指定任何参数。
【讨论】:
【参考方案2】:shell
参数在文档中的描述是a little hidden,即使这样,它也需要一些知识才能知道它到底做了什么。
简短的版本是它是一个模式标志,在shell=True
模式下,它期望参数是单个字符串,如下所示:
# I'm using subprocess.run instead of subprocess.call, they are very similar in
# what they do but subprocess.run has a nicer interface
from subprocess import run
>>> run('ls -l', shell=True)
total 0
-rw-r--r-- 1 root root 0 Aug 26 16:36 file_a.txt
-rw-r--r-- 1 root root 0 Aug 26 16:36 file_b.txt
CompletedProcess(args='ls -l', returncode=0)
在shell=False
模式下,它期望命令作为字符串列表,它会在内部将其转换为正确的调用。这通常是可取的,因为正确解析 shell 命令最终会非常棘手:
# this is the equivalent shell=False command
>>> run(['ls', '-l'], shell=False)
total 0
-rw-r--r-- 1 root root 0 Aug 26 16:36 file_a.txt
-rw-r--r-- 1 root root 0 Aug 26 16:36 file_b.txt
CompletedProcess(args=['ls', '-l'], returncode=0)
在标准库中有一个专门用于 shell 词法分析的完整模块,称为 shlex
,通过使用 shell=False
模式,您将永远不必弄乱它,这很好。
到目前为止,您的示例是一种特殊情况,因为该命令仅包含一个参数,在这种情况下,两种模式都稍微宽松一点,并假装它们可以处理任何一种形式的输入-单个字符串或列表字符串。
但是一旦你有两个参数,它们的行为就会不同:
# shell=True with an argument list, only runs the "ls" part, not "ls -l"
>>> run(['ls', '-l'], shell=True)
file_a.txt file_b.txt
CompletedProcess(args=['ls', '-l'], returncode=0)
# and shell=False with two arguments as a non-list fares even worse
>>> run('ls -l', shell=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/subprocess.py", line 423, in run
with Popen(*popenargs, **kwargs) as process:
File "/usr/lib/python3.6/subprocess.py", line 729, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.6/subprocess.py", line 1364, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'ls -l': 'ls -l'
【讨论】:
【参考方案3】:如果 shell 为 True,指定的命令将通过 shell 执行。如果您将 Python 主要用于它在大多数系统 shell 上提供的增强控制流,并且仍然希望方便地访问其他 shell 功能,例如 shell 管道、文件名通配符、环境变量扩展和 ~ 到用户家的扩展,这将很有用目录。但是,请注意 Python 本身提供了许多类似 shell 的功能的实现(特别是 glob、fnmatch、os.walk()、os.path.expandvars()、os.path.expanduser() 和 shutil)。
咨询:
https://docs.python.org/2/library/subprocess.html#frequently-used-arguments
章节:17.1.1.1。常用参数
【讨论】:
但是当我使用subprocess.call("ifconfig", shell=False)
时为什么没有任何变化?
您希望改变什么? ifconfig
是二进制可执行文件。它可以通过或不通过 shell 运行,但由于它不使用 shell 的任何功能,因此在这里没有任何区别。如果您在此处调用ifconfig *
,则会有所不同,如果shell=True
在这里,*
将被shell 扩展,对于shell=False
,它只会将*
作为命令行参数传递给@987654329 @.
谢谢!我不知道它没有使用shell的任何功能!以上是关于为啥 shell=True 和 shell=False 做同样的事情? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥不在 Python 中的 subprocess.Popen 中使用 `shell=True`? [复制]
shell简单命令与if语句,从这里开始shell的学习之路