Python 来自已完成子流程的stdout.read()有时返回空?

Python 来自已完成子流程的stdout.read()有时返回空?,python,subprocess,stdout,status,Python,Subprocess,Stdout,Status,我创建了一个字典,其中我将id与子流程关联。 比如: cmd = "ls" processes[id] = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE) 然后我用这个流程图作为输入调用一个方法,检查哪个流程已经完成。如果进程完成,我将检查进程的stdout.read(),以查找特定的字符串匹配 问题有时是stdout.read()返回一个空值,这会导致字符串匹配出现问题 示例代码: #Create a map proce

我创建了一个字典,其中我将id与子流程关联。 比如:

cmd = "ls"
processes[id] = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE)
然后我用这个流程图作为输入调用一个方法,检查哪个流程已经完成。如果进程完成,我将检查进程的
stdout.read()
,以查找特定的字符串匹配

问题有时是
stdout.read()
返回一个空值,这会导致字符串匹配出现问题

示例代码:

#Create a map
processes[id] = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE)
...
#Pass that map to a method which checks which processes have finished
completedProcesses(processes)

def completedProcesses(processes):
    processList = []
    for id,process in processes.iteritems():
        if process.poll() is not None:
            #If some error in process stdout then print id
            verifySuccessStatus(id, processes[id])
            processList.add(id)

def verifySuccessStatus(id, process):
    file=open(FAILED_IDS_FILE, 'a+')
    buffer =  process.stdout.read() #This returns empty value sometime
    if 'Error' not in buffer:
        file.write(id)
        file.write('\n')
    file.close()

我是python新手,我可能缺少对子流程的一些内部功能理解,您只是在阅读标准代码并查找“错误”。也许您还应该查看
stderr

processes[id] = subprocess.Popen(
    [cmd], 
    shell=True, 
    stdout=subprocess.PIPE, 
    stderr=subprocess.STDOUT,
    )
从:

子流程。STDOUT

一个特殊值,可用作Popen的stderr参数,并指示标准错误应与标准输出放在同一个句柄中

进程可能意外失败,返回的不是标准输出,而是非零返回代码。您可以使用
process.returncode
检查此项

Popen.返回代码

子返回代码,由poll()和wait()设置(间接由communicate()设置)。None值表示进程尚未终止

负值-N表示子级被信号N终止(仅限Unix)


根据您的
ls
示例命令判断,您的问题可能是由标准输出管充满引起的。使用
process.communicate()
方法为您处理此情况,因为您不需要多次写入
stdin

# Recommend the future print function for easier file writing.
from __future__ import print_function

# Create a map
# Keeping access to 'stderr' is generally recommended, but not required.
# Also, if you don't know you need 'shell=True', it's safer practice not to use it.
processes[id] = subprocess.Popen(
    [cmd],
    shell=True,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    )
...
#Pass that map to a method which checks which processes have finished
check_processes(processes)

def check_processes(processes):
    process_ids = []

    # 'id' is a built-in function in python, so it's safer to use a different name.
    for idx, process in processes.iteritems():
        # When using pipes, communicate() will handle the case of the pipe
        # filling up for you.
        stdout, stderr = process.communicate()
        if not is_success(stdout):
            write_failed_id(idx)
        process_ids.append(idx)

def is_success(stdout):
    return 'Error' not in stdout

def write_failed_id(idx):
    # Recommend using a context manager when interacting with files.
    # Also, 'file' is a built-in function in python.
    with open(FAILED_IDS_FILE, 'a+') as fail_file:
        # The future print function makes file printing simpler.
        print(idx, file=fail_file)

至少有两个问题:

  • 多次调用
    process.stdout.read()
    没有意义
    .read()
    在EOF之前不会返回。它返回一个空字符串,以指示在此之后的EOF
  • 您应该在进程仍在运行时读取管道,否则如果它们生成足够的输出来填充操作系统管道缓冲区(在我的Linux机器上约65K),它们可能会挂起

  • 如果要同时运行多个外部进程,并在完成后检查其输出,请参阅。

    检查代码部分格式您的意思是“error”而不是“error”吗注意缺少的引号esplz将其读取为“error”不在缓冲区中:@AFH大多数用户无法进行单字符编辑。但是,您可以作为原始海报进行编辑,将其更正为“错误”。您确实意识到check_输出将执行大多数代码正在执行的操作,并且不需要shell=True?输出在标准输出中。我有时看到缓冲区,但有时它是空的。即使进程终止,缓冲区是否仍保持完好?@AFH我不知道。您是否希望进程终止?这不是最初的问题,所以只是想知道,因为这是一个有趣的可能性。您是否检查了流程返回代码?如果您不希望进程终止,它将告诉您哪个信号终止了它。