理解python subprocess.check_output的第一个参数和shell = True

use*_*997 8 python linux shell subprocess

我对如何正确使用Python的子进程模块感到困惑,特别是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'
Run Code Online (Sandbox Code Playgroud)

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

>>> 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
Run Code Online (Sandbox Code Playgroud)

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

>>> subprocess.check_output("echo Hello World!", shell=True)
'Hello World!\n'
Run Code Online (Sandbox Code Playgroud)

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

Bak*_*riu 11

来自以下文件Popen:

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

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

Popen(['/bin/sh', '-c', args[0], args[1], ...])
Run Code Online (Sandbox Code Playgroud)

在Windows上shell=True,COMSPEC环境变量指定默认shell.您需要shell=True在Windows 上指定的唯一时间是您希望执行的命令是否内置到shell中(例如dircopy).您不需要shell=True运行批处理文件或基于控制台的可执行文件.

在您的情况下,由于echo是在启动时内置的shell shell=True,如果要将参数传递给echo命令,则必须将命令作为字符串写入,或者将整个命令作为字符串作为第一个元素传递给序列.序列的其他元素作为参数传递给shell,而不是传递给您正在调用的命令.

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

调用时引发的错误:

subprocess.check_output("echo Hello World!")
Run Code Online (Sandbox Code Playgroud)

是由于这样的事实,因为我们还没有使用shell=True,蟒蛇正试图执行该程序echo Hello World!即有名称的程序echo<space>Hello<space>World!.它一个有效的程序名称,但是你没有带有该名称的程序,因此是例外.

  • 这似乎是一个 API 设计缺陷。`shell` 是 `True/False` 并不足以证明第一个参数(命令)的含义发生这种剧烈(但无声)的变化是合理的。顺便说一句,新的 [`asyncio` 模块](http://docs.python.org/3.4/library/asyncio-eventloop.html#running-subprocesses) 使用两个不同的函数:`subprocess_exec` 和 `subprocess_shell` 来运行一个子进程和相应的 shell 命令。 (2认同)