为什么我们在运行subprocess.check_output(xyz,shell = True)之后从终端丢失stdout?

时间:2018-12-16 13:57:59

标签: python bash subprocess

我有这条bash行:

$ printf '  Number of xml files: %s\n' `find . -name '*.xml' | wc -l`
  Number of xml files: 4
$

当我以这种方式从python运行时, python解释器停止,并且我的终端机不再具有stdout ::

$ ls
input aa bb
$ python
Python 3.6.7 (default, Oct 22 2018, 11:32:17) 
>>>
>>> import subprocess
>>> cmd = "printf  'xml files: %s\n' `find . -name '*.xml' | wc -l`"
>>> subprocess.check_output(['/bin/bash', cmd], shell=True)
$ ls  # stdout is not seen any more I have to kill this terminal
$

显然,这里的问题不是如何使python的bash起作用:

>>> import subprocess
>>> cmd = "printf  'xml files: %s\n' `find . -name '*.xml' | wc -l`"
>>> out = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE)
>>> print(str(out.stdout, 'utf8'))
xml files: 4

>>> 

以下两个问题No output from subprocess.check_output()Why is terminal blank after running python executable?无法回答问题

1 个答案:

答案 0 :(得分:1)

简短的版本是check_output正在缓冲所有输出以返回。运行ls时,其标准输出将到达check_output的缓冲区,而不是终端。退出当前所在的外壳程序后,您将作为单个Python字符串一次获得所有输出。

这导致了一个问题,为什么首先要获得一个子shell,而不是执行cmd的内容?首先,您使用bash错误;它的参数是要运行的 file ,而不是任意命令行。您正在做的事情的更正确版本是

cmd = "printf  'xml files: %s\n' `find . -name '*.xml' | wc -l`"
subprocess.check_output(['/bin/bash', '-c', cmd])

或者,如果您希望subprocess为您运行一个shell,而不是显式执行它,

subprocess.check_output(cmd, shell=True)

将列表参数与shell=True组合在一起几乎不是您想要的。

第二,给定您的原始代码,check_output首先尝试将您的列表合并为一个字符串,然后将其与sh -c联接。也就是说,您尝试执行类似

的操作
sh -c /bin/bash "printf  'xml files: %s\n' `find . -name '*.xml' | wc -l`"

sh运行/bin/bash,并且您的命令字符串仅用作sh的附加参数,出于这个问题的目的,我们可以假定它被忽略了。因此,您处于交互式外壳中,如本答案第一部分所述,该外壳的标准输出被缓冲而不是显示。