如何使用Python Popen打印和存储通信和返回代码



这是我正在创建的函数,我有一个参数可以告诉是否实时打印,因为某些过程需要一个小时。 而且由于我同时处理了几个,因此另一个参数可以引发错误并停止所有内容,或者只是让主脚本运行。

但是如果我print_real_time True,我会丢失 p.communication((我可以将 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("nnSubprocess 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

谢谢大家=(

问题的一个可能的解决方案是在True print_real_time时将标准输出流存储在列表中,然后使用列表的内容生成标准输出数据字符串。如果未True print_real_time,则改用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("nnSubprocess 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

作为旁注,我还敦促您尝试重写程序,以便在Popen调用中不使用shell=True。它可能需要您将输入cmd预处理到基本命令和参数列表中,但通常认为使用 shell=True 是一个坏主意。

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("nnpopen 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

最新更新