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

时间:2014-01-09 19:17:21

标签: 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'

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

>>> 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'

所以我有点困惑,当第一个arg在一个没有shell=True的列表中然后作为一个简单的字符串WITH shell=True时,它就有效。我不理解shell=True做了什么以及将第一个arg作为列表与字符串传递之间的区别。

2 个答案:

答案 0 :(得分:10)

来自Popen的文档:

  

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

     

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

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

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

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

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

调用时出现的错误:

subprocess.check_output("echo Hello World!")

是因为你使用shell=True,因此python正在尝试执行程序echo Hello World!,即名为{{1的程序}}。 是一个有效的程序名,但是你没有带有该名称的程序,因此是例外。

答案 1 :(得分:0)

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