【问题标题】:Catching Terminal Output in Python在 Python 中捕获终端输出
【发布时间】:2013-09-27 20:12:00
【问题描述】:

我想做类似于这里的第二个答案的事情(但不太相似):Simulate Ctrl-C keyboard interrupt in Python while working in Linux

它更简单,我想我只是错过了一些东西。比如说,从 python 脚本中,我只想调用 'ping' 并在第 10 次之后终止它。我正在尝试像上面的链接那样做:

p = subprocess.Popen(['ping', 'google.com'], stdout=subprocess.PIPE)
for line in p.stdout:
  print line
  if re.search('10', line):
    break
os.kill(p.pid, signal.SIGINT)

但它不起作用。

我还希望显示“ping”的常规输出。我该怎么做呢?

编辑:这实际上不是我想做的“ping”。我只是将它用作具有连续输出的命令的示例,我想及时终止它。

更具体地说,我正在运行旧版本的 BitTorrent(第 3 个答案中的 v5.0.9:Where to find BitTorrent source code?),我通过 python 脚本调用它。 bittorrent-console.py 是一个简单的终端版本,因此是“控制台”。它定期输出多行。比如:

saving:       filename
file size:    blah
percent done: 100.0
blah:         blahblah

我实际上是这样称呼它的:

subprocess.call(['./bittorrent-console.py', 'something.torrent'])

当我看到 'percent done:' 为 100.0 时,我想自动终止它。

编辑:我在 CentOS、Python 2.6 上运行。

【问题讨论】:

  • 还要注意10可能是IP地址的一部分
  • 是的,我意识到了这一点,但假设地址或时间中没有 10。但同样,这只是一个例子。可能是if re.search('icmp_seq=10'
  • 请注意,subprocess.Popensubprocess.call 在一个非常重要的细节上有所不同。前者是异步的,后者是同步的。在后一种情况下,当您调用os.kill() 时,应用程序已经死了,os.kill() 没有任何作用。
  • 啊。是的。确实如此。不过,我想继续使用call,因为当我尝试下面的答案时,输出没有滞后。它只是调用了 bittorrent-console 并让它运行。下载完成后我不知道如何终止它,除了键盘中断。
  • 您是否知道在脚本内部,call 之后,是否有一种方法可以获取我刚刚调用的进程 ID?

标签: python terminal output


【解决方案1】:

首先,您想使用p.stdout.readline。我不知道为什么,但for line in p.stdout 似乎没有刷新。也许它被缓冲了。

其次,您应该使用sys.stdout.write(line),因为print 总是附加一些东西。不过,在 Python 3 中,您可以使用 print(line, end="")

此外,您应该更喜欢 p.kill 而不是 os.kill。我不确定你为什么使用os.kill

import os
import signal
import subprocess
import sys

p = subprocess.Popen(['ping', 'google.com'], stdout=subprocess.PIPE)
while True:
    line = p.stdout.readline()

    sys.stdout.write(line)
    sys.stdout.flush()
    if '10' in line:
        break

p.kill()

【讨论】:

  • 我认为这可以解决问题。为ping 示例工作。稍后我会在我真正的工作上进行尝试。
  • 这输出不太好。由于 bittorrent-console 一次打印多行,因此每行写入和刷新需要时间。有什么方法可以让我使用 subprocess.call,捕获 '100.0' 并终止 bittorrent-console?
  • 不,没有。您可以将bufsize=0 传递给subprocess.Popen,但您无能为力(如果逐步给出行,解析子行可能会有所帮助,但我对此表示怀疑)。
  • 嗯,你的回答确实解决了我的问题。我不希望终端输出的缓慢更新。我需要它仍然看起来是实时的。我想我得另谋出路了。
【解决方案2】:

这正是你想要的,并且在我的 OS X 机器上完美运行:

import subprocess
import re

def get_output(cmd, until):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    ret = []
    while True:
        line = p.stdout.readline()
        ret.append(line)
        if re.search(until, line):
            break
    p.kill()
    return ret

 print ''.join(get_output(['ping', 'google.com'], until='10'))

【讨论】:

  • 同样,10ping 只是示例。
  • 我看不出这个答案不能回答你的问题。
  • 当然可以。但是你迭代了一个范围。当我看到模式“10”时,我想终止。
  • 我以为你的意思是“在 10 行输出之后”。无论如何,我已经相应地更新了我的答案。
猜你喜欢
  • 2014-05-18
  • 2021-09-30
  • 1970-01-01
  • 2020-04-20
  • 2017-09-17
  • 1970-01-01
  • 1970-01-01
  • 2011-05-23
相关资源
最近更新 更多