【问题标题】:Parsing pexpect output解析 pexpect 输出
【发布时间】:2013-11-25 00:12:39
【问题描述】:

我正在尝试实时解析程序块缓冲的输出,这意味着在进程结束之前输出不可用。我需要的只是逐行解析,过滤和管理输出中的数据,因为它可以运行几个小时。

我尝试使用 subprocess.Popen() 捕获输出,但是是的,正如您可能猜到的那样,Popen 无法管理这种行为,它会一直缓冲直到进程结束。

from subprocess import Popen, PIPE

p = Popen("my noisy stuff ", shell=True, stdout=PIPE, stderr=PIPE)
for line in p.stdout.readlines():
    #parsing text and getting data

所以我找到了 pexpect,它实时打印输出,因为它将标准输出视为一个文件,或者我什至可以做一个肮脏的把戏,打印出一个文件并在函数之外解析它。但是好吧,它太脏了,即使对我来说也是如此;)

import pexpect
import sys

pexpect.run("my noisy stuff", logfile=sys.stdout)

但我想这应该是一种更好的 Pythonic 方式,只需像子进程一样管理标准输出。波本可以。我该怎么做?

编辑:

运行 J.F. 提案:

这是一次故意错误的审核,大约需要 25 秒。停下来。

from subprocess import Popen, PIPE

command = "bully mon0 -e ESSID -c 8 -b aa:bb:cc:dd:ee:00 -v 2"

p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE)

for line in iter(p.stdout.readline, b''):
    print "inside loop"
    print line

print "outside loop"
p.stdout.close()
p.wait()


#$ sudo python SCRIPT.py
                                ### <= 25 secs later......
# inside loop
#[!] Bully v1.0-21 - WPS vulnerability assessment utility

#inside loop
#[!] Using 'ee:cc:bb:aa:bb:ee' for the source MAC address

#inside loop
#[X] Unable to get a beacon from the AP, possible causes are

#inside loop
#[.]    an invalid --bssid or -essid was provided,

#inside loop
#[.]    the access point isn't on channel '8',

#inside loop
#[.]    you aren't close enough to the access point.

#outside loop

改用此方法: 编辑:由于输出中的大量延迟和超时,我不得不修复孩子,并添加了一些技巧,所以最终代码看起来像这样

import pexpect

child = pexpect.spawn(command)
child.maxsize = 1  #Turns off buffering
child.timeout = 50 # default is 30, insufficient for me. Crashes were due to this param.
for line in child:
    print line,

child.close()

返回相同的输出,但它实时打印行。所以...解决了谢谢@J.F.塞巴斯蒂安

【问题讨论】:

  • 您需要发送对命令的回复还是只是读取输出?对于可能运行数小时的程序,您需要行缓冲输出还是块缓冲输出(例如,使用 4096 字节缓冲区)就足够了?
  • 嗨,J.F. 我只需要解析输出。该程序本身审核数据流,因此我想根据该程序的输出行为管理其他程序。所以我的代码会不断读取输出。
  • 使用print line,(注意:逗号结尾——sys.stdout.softspace hack)来避免重复换行。

标签: python parsing subprocess output pexpect


【解决方案1】:

.readlines() 读取所有行。难怪在子流程结束之前您看不到 任何 输出。只要子进程刷新其标准输出缓冲区,您就可以使用.readline() 来逐行读取:

from subprocess import Popen, PIPE

p = Popen("my noisy stuff", stdout=PIPE, bufsize=1)
for line in iter(p.stdout.readline, b''):
    # process line
    ..
p.stdout.close()
p.wait()

如果您已经拥有pexpect,那么您可以使用它来解决块缓冲问题:

import pexpect

child = pexpect.spawn("my noisy stuff", timeout=None)
for line in child: 
    # process line
    ..
child.close()

另请参阅我在 cmets 中链接的问题中的 stdbuf, pty -based solutions

【讨论】:

  • 这段代码仍然不起作用,因为某些应用程序有一个块缓冲输出,所以流出缓冲区的唯一方法是从伪 pty 运行命令。我在 S.Overf 看过你的其他 cmets。我在问之前都试过了;)。 Pexpect 是一种有效的方法......正如预期的那样。
  • @peluzza:我已经明确添加了pexpect 解决方案。您能否更新您的问题以提供一个完整的最小示例,以使用我的答案中的subprocess 代码演示在您的特定情况下“不起作用”的含义? (例如,"my noisy stuff"'{ echo a; sleep 2; echo b;}', shell=True 并且在不等待 2 秒的情况下获取 'a' 至关重要)
  • 已编辑,我粘贴了术语输出。无论如何,您的 pexpect 解决方案就像魅力一样。实时打印输出。非常感谢。!!!
  • @是的,但仍然是相同的输出。我想在循环的每次迭代中清理缓冲区是个好主意。
  • @peluzza:你可以设置timeout=None 禁用超时(默认30秒)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 2022-12-22
  • 2013-08-09
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多