在Python中替换subprocess.PIPE?

问题描述 投票:0回答:3

我正在使用 subprocess 模块与 Linux 命令的输出进行交互。下面是我的代码。

import subprocess
import sys

file_name = 'myfile.txt'
p = subprocess.Popen("grep \"SYSTEM CONTROLLER\" "+ file_name, stdout=subprocess.PIPE, shell=True)
(output, err) = p.communicate()
print output.strip()

p = subprocess.Popen("grep \"controller\|worker\" "+ file_name, stdout=subprocess.PIPE, shell=True)
(output, err) = p.communicate()
lines = output.rstrip().split("\n")
print lines

我的程序在执行第二个子进程时挂起,即

p = subprocess.Popen("grep \"controller\|worker\""+ file_name,stdout=subprocess.PIPE, shell=True)

我了解到进程挂起的原因是缓冲区重定向到子进程。PIPE 正在被填满,这会阻止进程进一步写入。

我想知道是否有任何方法可以避免缓冲区已满的情况,以便我的程序继续执行而不会出现任何挂起问题?

python python-2.7 python-3.x
3个回答
4
投票

实际问题是模式和文件名之间缺少空格,因此

grep
等待标准输入(stdin)上的输入。

“缓冲区已满”

.communicate()
不易受影响)或
p.stdout.read()
(它没有修复任何内容:它将输出加载到内存中,与
.communicate()
不同,如果使用多个管道,它会失败)在这里是一种转移注意力的方法.

删除

shell=True
并使用命令的列表参数:

#!/usr/bin/env python
from subprocess import Popen, PIPE

p = Popen(["grep", r"controller\|worker", file_name], stdout=PIPE)
output = p.communicate()[0]
if p.returncode == 0:
    print('found')
elif p.returncode == 1:
    print('not found')
else: 
    print('error')

3
投票

正如它所说的https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate

注意: 读取的数据缓冲在内存中,所以不要使用此方法 如果数据量很大或没有限制。

相反,请使用 文件对象 来读取生成的文本:

output = p.stdout.read()

只要您阅读时没有其他管道(例如 stderr)被填满,该进程就不应被阻塞。


0
投票

如果大小成为问题,请切换到临时文件

tempfile.SpooledTemporaryFile
并通过

进行通信
import templfile
import time

stdout = tempfile.SpooledTemporaryFile(mode="w+")
process = subprocess.Popen(.., .., stdout=stdout)

while process.poll() is None:
    time.sleep(1)

stdout.seek(0)
stdout = stdout.read()
stdout.close()

对象

SpooledTemporaryFile 
仅当内容变得充实时才从内存切换到文件存储。

© www.soinside.com 2019 - 2024. All rights reserved.