为啥 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`? [复制]

DAY11 Shell脚本基础(Enginner05-2)

shell简单命令与if语句,从这里开始shell的学习之路

PHP调用shell命令,怎么实现,我为啥shell_exec的返回值总是null呢

服务账号为啥要禁止shell

为啥 spark-shell 因 NullPointerException 而失败?