了解python subprocess.check_output的第一个参数和shell = True [重复]

Posted

技术标签:

【中文标题】了解python subprocess.check_output的第一个参数和shell = True [重复]【英文标题】:Understanding python subprocess.check_output's first argument and shell=True [duplicate] 【发布时间】:2014-01-28 12:44:53 【问题描述】:

我对如何正确使用 Python 的 subprocess 模块感到困惑,特别是 check_output 方法的第一个参数和 shell 选项。查看下面交互式提示的输出。我将第一个参数作为列表传递,根据是否设置了shell=True,我得到不同的输出。有人可以解释这是为什么以及输出的输出吗?

>>> import subprocess
>>> subprocess.check_output(["echo", "Hello World!"])
'Hello World!\n'
>>> subprocess.check_output(["echo", "Hello World!"], shell=True)
'\n'

现在,当我将第一个参数作为简单字符串而不是列表传递时,我得到了这个讨厌的堆栈跟踪。为什么会这样,这里发生了什么?

>>> subprocess.check_output("echo Hello World!")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 537, in check_output
process = Popen(stdout=PIPE, *popenargs, **kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1228, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory

但是,当我打开 shell=True 时,它​​会完美运行:

>>> subprocess.check_output("echo Hello World!", shell=True)
'Hello World!\n'

所以我有点困惑,当第一个参数在没有shell=True 的列表中,然后作为带有shell=True 的简单字符串时,它可以工作。我不明白 shell=True 的作用以及将第一个 arg 作为列表与字符串传递之间的区别。

【问题讨论】:

【参考方案1】:

来自Popen的文档:

shell 参数(默认为False)指定是否使用 shell 作为要执行的程序。如果 shell 是True,它是 建议将args 作为字符串而不是序列传递。

在带有shell=True 的Unix 上,shell 默认为/bin/sh如果 args 是 字符串,字符串指定要通过shell执行的命令。 这意味着字符串必须完全按照它的格式进行格式化 在 shell 提示符下键入时。这包括,例如,引用或 反斜杠转义带有空格的文件名。 如果 args 是 序列,第一项指定命令字符串,任何 附加项将被视为 shell 的附加参数 本身。也就是说,Popen 相当于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

在带有shell=True 的 Windows 上,COMSPEC 环境变量指定 默认外壳。唯一需要指定shell=True on Windows 是您希望执行的命令内置于 外壳(例如dircopy)。您不需要shell=True 来运行批处理 文件或基于控制台的可执行文件。

在您的情况下,由于echo 是使用shell=True 启动时内置的shell,如果您想将参数传递给echo 命令,您必须将命令编写为一个字符串或传递一个具有 whole 命令的序列作为第一个元素的字符串。序列的其他元素作为参数传递到 shell,而不是你正在调用的命令。

一些操作系统中,echo也是一个程序(通常是/bin/echo)。这解释了为什么您的第一个示例没有引发异常而是输出 '\n' 而不是预期的 'Hello, World!\n'/bin/echo 命令在没有参数的情况下执行,因为该参数已被 shell“消耗”。

调用时出现的错误:

subprocess.check_output("echo Hello World!")

是因为,因为你没有使用shell=True,python 正在尝试执行程序echo Hello World!,即名称为echo&lt;space&gt;Hello&lt;space&gt;World! 的程序。它一个有效的程序名称,但你没有该名称的程序,因此例外。

【讨论】:

这似乎是一个 API 设计缺陷。 shellTrue/False 不足以证明第一个参数(命令)的含义发生如此剧烈(但无声)的变化。顺便说一句,新的asyncio module 使用了两个不同的函数:subprocess_execsubprocess_shell 分别运行一个子进程和一个 shell 命令。 @J.F.Sebastian 他们可能应该添加一个shell_args 参数而不是重复使用args 是的,len(args) &gt; 1 and shell=True 在大多数情况下是一个错误。【参考方案2】:

任何时候你使用shell=True,你输入一个带引号的字符串作为check_output的第一个参数,代表你通常输入到shell中的内容。 “在 shell=True 的 Unix 上,shell 默认为 /bin/sh。”这为您提供了所有 shell 功能。 “这意味着字符串的格式必须与在 shell 提示符下键入时完全相同。” See Popen

【讨论】:

以上是关于了解python subprocess.check_output的第一个参数和shell = True [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Python subprocess.check_output()

当父进程死亡时,如何杀死使用 subprocess.check_output() 创建的 python 子进程?

python: subprocess.check_output 如何创建它的调用?

Python子进程subprocess.check_output和journalctl游标

如何从 Python subprocess.check_output() 捕获异常输出?

python3 subprocess.check_output的使用