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

时间:2018-02-12 09:30:14

标签: python linux parallel-processing subprocess pipe

我有一个命令,其输出我正在写入文件并使用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()或无法等待该过程完成。

3 个答案:

答案 0 :(得分:2)

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')

根据您的工作情况,您可能需要以不同方式构建代码。

答案 1 :(得分:0)

缓冲可能是一个问题。

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

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

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

管道示例

由于您希望能够在启动过程后立即阅读,因此您可以使用Pipesubprocess.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,因为我不确定是否有充分的理由使用它,但这是一个很大的安全问题。

答案 2 :(得分:0)

如果您不想等到执行结束,其中一个选项是在另一个线程中读取:

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()