运行并从后台进程获取输出

Posted

技术标签:

【中文标题】运行并从后台进程获取输出【英文标题】:Run and get output from a background process 【发布时间】:2012-05-15 16:22:42 【问题描述】:

我已经知道有几个针对这个主题的问题,但没有一个能解决我的具体问题。或者至少我找不到它。

我需要在后台执行一些程序,等待输出并对其进行操作。 但后台程序必须继续执行

我需要的后台程序的信息准确地位于其输出的第二行。如果这个程序阻止我的代码直到到达这一行,就没有问题。但它必须在该行之后解锁,以便我可以执行与后台程序完全无关的其他任务。

不过,我不知道如何实现这一点。我已经阅读了很多subprocess 模块的文档,尤其是subprocess.Popen

务实:为什么this code 不适用于['localtunnel', '8000'] 参数?它什么也不输出...

我知道我不需要 root 权限来执行此操作。


在 jadkik94 和 fest 回答后编辑

不幸的是,这两个答案都不适合我。也许我做错了什么......

首先。 “健全性检查”:

import subprocess, threading, time
can_break = False

def run():
    args = ["ping", "google.com"]
    popen = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE)
    while not can_break:
        print popen.stdout.readline()

t = threading.Thread(target=run)

try:
    t.start()
    while True:
        print 'Main thread...'
        time.sleep(1)
except KeyboardInterrupt:
    can_break = True

上面的代码可以正常工作,输出类似于:

Main thread...
PING google.com (74.125.234.160) 56(84) bytes of data.
64 bytes from plusone.google.com (74.125.234.160): icmp_req=1 ttl=54 time=82.5 ms
Main thread...
64 bytes from plusone.google.com (74.125.234.160): icmp_req=2 ttl=54 time=82.7 ms
[...]

但是当我将它与我想要的args (args = ['localtunnel', 8000]) 一起使用时,唯一的输出是Main thread...

当我在主线程(阻塞)中调用localtunnel 时,它会返回所需的输出:

In [x]: popen = subprocess.Popen(['localtunnel', '8000'])
  This localtunnel service is brought to you by Twilio.
  Port 8000 is now publicly accessible from http://????.localtunnel.com ...

这种方法基于 jadkik94 的回答。但是 fest 的回答也不起作用。

【问题讨论】:

明确一点:Python 脚本是否需要第二行以外的任何后台程序输出?还是只需要让它继续运行? 第二行之后,后台程序可以“隐藏”它的输出。 【参考方案1】:

要以非阻塞方式启动程序但仍能看到程序的输出,程序必须在单独的线程或进程中启动。 Ryan 在这里发布了一个不错的代码示例:Python Subprocess.Popen from a thread

请记住,最后一行 print myclass.stdout 将打印输出当时的显示方式。如果程序刚刚启动,它可能根本没有输出任何东西,所以你的代码可能应该从myclass.stdout 读取,直到它收到你需要的行。

【讨论】:

【参考方案2】:

您可以在线程中运行它(这样它就不会阻止您的代码运行),并在获得第二行之前获取输出,然后等待它终止。这是一个示例,它将读取 Windows 上命令 dir /s 的输出以获取所有目录列表。

import subprocess, thread, time

def run():
    global can_break

    args = ["dir", "/s"]
    shell = True

    count = 0
    popen = subprocess.Popen(args, shell=shell, stdout=subprocess.PIPE)
    while True:
        line = popen.stdout.readline()
        if line == "": continue
        count += 1
        if count == 2:
            do_something_with(line)
            break

    print "We got our line, we are waiting now"
    popen.wait()
    print "Done."
    can_break = True

def do_something_with(line):
    print '>>> This is it:', line

thread.start_new_thread(run, tuple())

can_break = False
while not can_break:
    print 'Wait'
    time.sleep(1)

print 'Okay!'

输出将如下所示:

等待 >>> 这是它:卷序列号是 XXXX-XXXX 我们得到了我们的线路,我们现在正在等待 等待 等待 等待 . . . 完毕。 等待 好的!

【讨论】:

看来你有问题 1)它在线程中运行(我们有问题)2)你传递给subprocess.Popen的参数。所以试着在一个线程中运行它,就像你在主线程中一样:subprocess.Popen(args) 还有一件事:带 args 的输出是“主线程...”,是否有新行?应该有很多新行,因为popen.stdout.readline() 应该返回一些东西……而你正在打印它。我会尝试让localtunnel 在这里运行,我自己看看。 没有新行。我认为这是因为 popen.stdout.readline() 阻塞直到它有数据。但是我现在才注意到一个奇怪的事情是,当我在几个Main thread...之后杀死程序时,它出现了localtunnel的第一行:This service is localtunnel Brought to you by Twilio.。但就在我杀死整个程序时(使用 CTRL+C)。 当我将subprocess.Popen(args) 放在第二个线程中时它可以工作(code here)。但是现在我不知道如何捕获和读取输出。 我忘了在我的第一条评论中添加:这似乎表明 popen 输出以某种方式被缓冲了。

以上是关于运行并从后台进程获取输出的主要内容,如果未能解决你的问题,请参考以下文章

Linux系统理论操作学习26LInux的后台运行,重定向输出,前后台进程转换和管理

Linux 进程在后台运行

如果我们关闭它启动的终端,linux 会杀死后台进程吗?

从后台进程获取 PID 作为另一个用户运行

如何在servlet中获取后台运行脚本的输出

Linux nohup和&后台运行,进程查看及终止,进程信息输出,控制台信息输出