在第一行之后杀死子进程

Killing subprocess after first line

我正在执行从 python.
连接到外部服务器的程序 如果用户未通过身份验证,程序会要求输入用户名和密码。

这是子程序输出的样子:

Authentication Required

Enter authorization information for "Web API"

<username_prompt_here>
<password_prompt_here>

我想在打印 'Authentication Required' 后立即终止子进程,但问题是,我的代码运行错误 - 子进程要求凭据,在用户提供凭据后,子进程被终止。

这是我的代码:

with subprocess.Popen(self.command, stdout=subprocess.PIPE, shell=True, bufsize=1, universal_newlines=True) as process:
    for line in process.stdout:
        if 'Authentication Required' in line:
            print('No authentication')
            process.kill()
        print(line)

我做错了什么?

What am I doing wrong?

如果子进程及时刷新其标准输出缓冲区,您的代码就可以了(如果您想在 'Authentication Required' 行之后终止子进程,而不管其位置如何)。参见 Python: read streaming input from subprocess.communicate()

观察到的行为表明子进程使用块缓冲模式,因此您的父脚本看到 'Authentication Required' 行太晚了,或者用 process.kill() 杀死 shell 并没有t kill它的后代(命令创建的进程)。

解决方法:

  • 查看是否可以传递命令行参数,例如 --line-buffered(被 grep 接受),以强制使用行缓冲模式
  • 或者查看 stdbufunbufferscript 实用程序是否适用于您的情况
  • 或者提供一个伪 tty 来欺骗进程,使其认为它直接在终端中运行——它也可能会强制使用行缓冲模式。

参见以下代码示例:

  • Python subprocess readlines() hangs
  • Python C program subprocess hangs at "for line in iter"
  • Last unbuffered line can't be read

And - not always I want to kill program after first line. Only if first line is 'Authentication required'

假设块缓冲问题已解决,如果第一行包含 Authentication Required:

则终止子进程
with Popen(shlex.split(command), 
           stdout=PIPE, bufsize=1, universal_newlines=True) as process:
    first_line = next(process.stdout)
    if 'Authentication Required' in first_line:
        process.kill()
    else: # whatever
        print(first_line, end='')
        for line in process.stdout:
            print(line, end='')

如果您的情况需要 shell=True,请参阅 How to terminate a python subprocess launched with shell=True