繁体   English   中英

使用subprocess.Popen启动子进程并在运行时读取其输出

[英]Start child process with subprocess.Popen and read its output while it is running

我有一个命令,该命令的输出将写入文件并使用subprocess.Popen调用该命令。 这是一个示例:

stdout_output = open('testfile.txt','w')
process = subprocess.Popen(command,stdout=stdout_output,shell=True)
stdout_read = open('testfile.txt','r')
data = stdout_read.read()
print data

数据有时没有任何内容,但是当我在触发过程和读取数据之间添加一些睡眠时,例如

stdout_output = open('testfile.txt','w')
process = subprocess.Popen(command,stdout=stdout_output,shell=True)
time.sleep(3)
stdout_read = open('testfile.txt','r')
data = stdout_read.read()
print data

然后,数据包含写入文件的实际数据。 这里有我想念的东西吗? 还是有其他方法可以在触发过程和读取输出之间增加一些时间,而不是提供硬编码的睡眠。

-该命令正在进行中。 我无法添加process.wait()或无法等待进程完成后再读取文件。

Popen启动一个同时运行的新进程,因此,如果要可靠地获取该进程的输出,则必须等待该进程。 实际上, subprocess模块具有一个check_output函数,可以为您执行此操作:

data = subprocess.check_output(command, shell=True)
print data

显然,这是阻碍。


“等待”进程结束而不阻塞主进程的唯一方法是poll它。 但是,这要求您以定期检查的方式编写代码,并且当poll方法返回不同于None您可以读取过程的输出。

例如:

def do_stuff(proc, filename):
    # proc.poll() check if proc has ended
    while proc.poll() is None:
        print('Here you do whatever you want while you wait for the process')
        # do other stuff
        ping_pong.play()
    # here we are sure the command terminate and wrote his output
    proc.stdout.close()
    with open(filename) as f:
        return f.read()

stdout_file = open('some_file', 'w')
process = Popen(['command'], stdout=stdout_file)
output = do_stuff(process, 'some_file')

根据您正在执行的操作,您可能需要以不同的方式构造代码。

缓冲可能是个问题。

尝试打开文件以使用零长度缓冲区进行写入。 像这样:

stdout_output = open('testfile.txt','w', 0)

当然,命令可能不会立即产生输出,在这种情况下,您将需要有一个循环以不断尝试读取。

管道示例

由于您希望能够在启动过程后立即阅读,因此可以使用Pipe subprocess.Popen已经为您提供了一个选项,把stdint/stdout/stderr穿过。

这是带有示例bash脚本的Python代码示例,该脚本回显消息,休眠然后回显另一条消息。 请注意,Python代码必须知道子进程何时完成发送数据。

import subprocess

"""
notifier.sh
------------------

echo "This is me"
sleep 4
echo "This is me again"

------------------
"""

command = ['bash', 'notifier.sh']
process = subprocess.Popen(command, stdout=subprocess.PIPE)

while True:
    if process.poll() is not None:
        break
    data = process.stdout.readline()
    print data

我确实尝试通过此示例bash shell脚本来模拟用例。

另外,我确实删除了shell=True因为我不确定是否有充分的理由使用它,但这是一个很大的安全问题。

如果您不希望等到执行结束,则选项之一是在单独的线程中读取:

def reader(fd, finished):
    while not finished.is_set():
        data = fd.read()
        if data: print(data)
        time.sleep(SOME_TIMEOUT)

process = subprocess.Popen(command,stdout=stdout_output,shell=True)
finished = threading.Event()
reader_thread = threading.Thread(target=reader, args=(stdout_output, finished))
reader_thread.start()
process.wait()
finished.set()
reader_thread.join()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM