如何使用python popen打印并存储通信和返回代码?

时间:2017-05-19 16:28:20

标签: python printing subprocess popen

这是我正在创建的函数,我有一个参数可以告诉实时打印,因为某些过程需要一个小时。因为我同时对几个进行子处理,另一个引发错误并停止一切的参数,或者让主脚本运行。

但如果我执行print_real_time True,我将松开p.communicate() 我可以将iter中的所有打印件存储在变量中并返回,但是我如何将std输出和stderr,并获取返回值以查看是否失败?

def launch_subprocess_cmd(command_to_lunch, cwd=None, print_real_time=False,    raise_errors=True):
"""
for a given command line will lunch that as a subprocess
:param command_to_lunch: string
:param print_real_time: boolean
:param cwd: the folder path from where the command should be run.
:param raise_errors: boolean if the return code of the subprocess is different than 0 raise an error an stop all scripts.
                        else the main script will keep running and can access the third return value of this function and decide what to do with it.
:return: list com return the stdout and the stderr of the Popen subprocess.
"""
if cwd is None:
    p = subprocess.Popen(command_to_lunch, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
else:
    p = subprocess.Popen(command_to_lunch, cwd=cwd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)

if print_real_time is True:
    for i in iter(p.stdout.readline, b''):
        print i

com = p.communicate()
if raise_errors is True:
    if p.returncode != 0:
        raise ValueError("\n\nSubprocess fail: \n" + "Error captures: \n" + "stdout:\n" + com[0] + "\nstderr:\n" + com[1] + "\n")
# com[0] is std_out, com[1] is std_err and p.return code is if the subprocess was successful or not with a int number
return com[0], com[1], p.returncode

谢谢你们=)

2 个答案:

答案 0 :(得分:1)

问题的一种可能解决方案是在print_real_timeTrue时将stdout流存储在列表中,然后使用列表内容生成stdout数据字符串。如果print_real_time不是True,请使用com[0]中的内容。

def launch_subprocess_cmd(cmd, cwd=None, print_real_time=False, raise_errors=True):
    """
    for a given command line will lunch that as a subprocess
    :param cmd: string
    :param print_real_time: boolean
    :param cwd: the folder path from where the command should be run.
    :param raise_errors: boolean if the return code of the subprocess is different
                         than 0 raise an error an stop all scripts else
                         the main script will keep running and can access the third
                         return value of this function and decide what to do with it.
    :return: list com return the stdout and the stderr of the Popen subprocess.
    """
    if cwd is None:
        p = subprocess.Popen(cmd, stderr=subprocess.PIPE,
                             stdout=subprocess.PIPE, shell=True)
    else:
        p = subprocess.Popen(cmd, cwd=cwd, stderr=subprocess.PIPE,
                             stdout=subprocess.PIPE, shell=True)

    stdout_list = []
    if print_real_time is True:
        for i in iter(p.stdout.readline, b''):
            stdout_list.append(i)
            print i

    com = p.communicate()
    stdout_data = "".join(stdout_list) if print_real_time is True else com[0]

    if raise_errors is True:
        if p.returncode != 0:
            raise ValueError("\n\nSubprocess fail: \n" + "Error captures: \n" +
                             "stdout:\n" + stdout_data + "\nstderr:\n" +
                             com[1] + "\n")
    # stdout_data is stdout, com[1] is stderr and
    # p.return code is if the subprocess was successful or not with a int number
    return stdout_data, com[1], p.returncode

作为旁注,我还建议您尝试将程序重写为shell=True来电中使用Popen。可能需要将输入cmd预处理为基本命令和参数列表,但使用shell=True通常被认为是个坏主意。

答案 1 :(得分:0)

launch_subprocess_cmd(command_to_lunch, cwd=None, print_real_time=False, raise_errors=True):
if cwd is None:
    p = subprocess.Popen(command_to_lunch, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
else:
    p = subprocess.Popen(command_to_lunch, cwd=cwd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)

stdout_list = []
errout_list = []
if print_real_time is True:
    for i in iter(p.stdout.readline, b''):
        stdout_list.append(i)
        print i
    for j in iter(p.stderr.readline, b''):
        errout_list.append(j)
        print j

com = p.communicate()
if print_real_time is True:
    stdout_data = "".join(stdout_list)
    std_err_data = "".join(errout_list)
else:
    stdout_data = com[0]
    std_err_data = com[1]

if raise_errors is True:
    if p.returncode != 0:
        raise ValueError("\n\npopen fail:\n" + command_to_lunch + "\nError:\n" + "Error captures:\n" + "stdout:\n" + stdout_data + "\nstderr:\n" + std_err_data + "\n")
# com[0] is out, com[1] is errors and p.return code is if it fail or not
return stdout_data, std_err_data, p.returncode