检查 python 中 运行 子进程的标准输出
Check on the stdout of a running subprocess in python
如果需要定期检查运行进程的stdout
。例如,进程是 tail -f /tmp/file
,它是在 python 脚本中生成的。然后每隔 x 秒,将该子进程的标准输出写入一个字符串并进行进一步处理。子进程最终被脚本停止。
解析子进程的标准输出,如果使用 check_output
直到现在,这似乎不起作用,因为进程仍然是 运行 并且不会产生明确的输出。
>>> from subprocess import check_output
>>> out = check_output(["tail", "-f", "/tmp/file"])
#(waiting for tail to finish)
应该可以为子进程使用线程,以便可以处理多个子进程的输出(例如tail -f /tmp/file1,tail -f /tmp/file2)。
如何以多线程友好的方式启动子进程、定期检查和处理其标准输出并最终停止子进程? python 脚本在 Linux 系统上运行。
目标不是连续读取文件,tail 命令就是一个例子,因为它的行为与实际使用的命令完全一样。
编辑:我没想通,文件不存在。 check_output
现在只需等待进程完成。
edit2: 使用 Popen
和 PIPE
的另一种方法似乎会导致同样的问题。它等待 tail
完成。
>>> from subprocess import Popen, PIPE, STDOUT
>>> cmd = 'tail -f /tmp/file'
>>> p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
>>> output = p.stdout.read()
#(waiting for tail to finish)
你的第二次尝试是 90% 正确。唯一的问题是您试图在完成后同时读取 tail
的 all 的标准输出。但是,tail
的目的是在后台 运行(无限期?),因此您确实想从中逐行读取 stdout:
from subprocess import Popen, PIPE, STDOUT
p = Popen(["tail", "-f", "/tmp/file"], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
for line in p.stdout:
print(line)
我删除了 shell=True
和 close_fds=True
参数。第一个是不必要的并且有潜在危险,而第二个只是默认设置。
请记住,文件对象在 Python 中的行上是可迭代的。 for
循环将 运行 直到 tail
结束,但它会处理出现的每一行,而不是 read
,它将阻塞直到 tail
结束.
如果我在 /tmp/file
中创建一个空文件,启动该程序并开始使用另一个 shell 将行回显到文件中,程序将回显这些行。您可能应该用更有用的东西替换 print
。
下面是我在启动上面的代码后键入的命令示例:
命令行
$ echo a > /tmp/file
$ echo b > /tmp/file
$ echo c >> /tmp/file
程序输出(来自 Python 在不同的 shell)
b'a\n'
b'tail: /tmp/file: file truncated\n'
b'b\n'
b'c\n'
如果您希望主程序在响应 tail
的输出时响应,请在单独的线程中启动循环。你应该让这个线程成为守护进程,这样它就不会阻止你的程序退出,即使 tail
没有完成。您可以让线程打开子进程,也可以只将标准输出传递给它。我更喜欢后一种方法,因为它可以让你在主线程中有更多的控制权:
def deal_with_stdout():
for line in p.stdout:
print(line)
from subprocess import Popen, PIPE, STDOUT
from threading import Thread
p = Popen(["tail", "-f", "/tmp/file"], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
t = Thread(target=deal_with_stdout, daemon=True)
t.start()
t.join()
这里的代码几乎相同,只是增加了一个新线程。我在末尾添加了一个 join()
,这样程序就可以很好地作为示例运行(join
等待线程在返回前结束)。您可能想用通常 运行ning.
的任何处理代码替换它
如果你的线程足够复杂,你可能还想继承Thread
并覆盖run
方法,而不是传入一个简单的target
。
如果需要定期检查运行进程的stdout
。例如,进程是 tail -f /tmp/file
,它是在 python 脚本中生成的。然后每隔 x 秒,将该子进程的标准输出写入一个字符串并进行进一步处理。子进程最终被脚本停止。
解析子进程的标准输出,如果使用 check_output
直到现在,这似乎不起作用,因为进程仍然是 运行 并且不会产生明确的输出。
>>> from subprocess import check_output
>>> out = check_output(["tail", "-f", "/tmp/file"])
#(waiting for tail to finish)
应该可以为子进程使用线程,以便可以处理多个子进程的输出(例如tail -f /tmp/file1,tail -f /tmp/file2)。
如何以多线程友好的方式启动子进程、定期检查和处理其标准输出并最终停止子进程? python 脚本在 Linux 系统上运行。
目标不是连续读取文件,tail 命令就是一个例子,因为它的行为与实际使用的命令完全一样。
编辑:我没想通,文件不存在。 check_output
现在只需等待进程完成。
edit2: 使用 Popen
和 PIPE
的另一种方法似乎会导致同样的问题。它等待 tail
完成。
>>> from subprocess import Popen, PIPE, STDOUT
>>> cmd = 'tail -f /tmp/file'
>>> p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
>>> output = p.stdout.read()
#(waiting for tail to finish)
你的第二次尝试是 90% 正确。唯一的问题是您试图在完成后同时读取 tail
的 all 的标准输出。但是,tail
的目的是在后台 运行(无限期?),因此您确实想从中逐行读取 stdout:
from subprocess import Popen, PIPE, STDOUT
p = Popen(["tail", "-f", "/tmp/file"], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
for line in p.stdout:
print(line)
我删除了 shell=True
和 close_fds=True
参数。第一个是不必要的并且有潜在危险,而第二个只是默认设置。
请记住,文件对象在 Python 中的行上是可迭代的。 for
循环将 运行 直到 tail
结束,但它会处理出现的每一行,而不是 read
,它将阻塞直到 tail
结束.
如果我在 /tmp/file
中创建一个空文件,启动该程序并开始使用另一个 shell 将行回显到文件中,程序将回显这些行。您可能应该用更有用的东西替换 print
。
下面是我在启动上面的代码后键入的命令示例:
命令行
$ echo a > /tmp/file
$ echo b > /tmp/file
$ echo c >> /tmp/file
程序输出(来自 Python 在不同的 shell)
b'a\n'
b'tail: /tmp/file: file truncated\n'
b'b\n'
b'c\n'
如果您希望主程序在响应 tail
的输出时响应,请在单独的线程中启动循环。你应该让这个线程成为守护进程,这样它就不会阻止你的程序退出,即使 tail
没有完成。您可以让线程打开子进程,也可以只将标准输出传递给它。我更喜欢后一种方法,因为它可以让你在主线程中有更多的控制权:
def deal_with_stdout():
for line in p.stdout:
print(line)
from subprocess import Popen, PIPE, STDOUT
from threading import Thread
p = Popen(["tail", "-f", "/tmp/file"], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
t = Thread(target=deal_with_stdout, daemon=True)
t.start()
t.join()
这里的代码几乎相同,只是增加了一个新线程。我在末尾添加了一个 join()
,这样程序就可以很好地作为示例运行(join
等待线程在返回前结束)。您可能想用通常 运行ning.
如果你的线程足够复杂,你可能还想继承Thread
并覆盖run
方法,而不是传入一个简单的target
。