使用子进程获取 pv 输出

Getting pv output with subprocess

我正在编写一个脚本来自动在 MySQL 中导入数据库。我正在尝试编写代码以在导入数据库时​​显示 pv 的输出:

    pv = subprocess.Popen(
        ["pv", "-f", restore_filepath],
        bufsize=1,
        stderr=subprocess.PIPE,
        stdout=subprocess.PIPE,
        universal_newlines=True,
        shell=True,
    )
    subprocess.Popen(
        [
            "mysql",
            "-u{}".format(db_user),
            "-p{}".format(db_pass),
            db_name,
        ],
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.DEVNULL,
        stdin=pv.stdout,
    )
    for line in pv.stderr:
        print("hello")
        sys.stdout.write("\r" + line.rstrip("\n"))
        sys.stdout.flush()

这是基于 中的代码,但它对我不起作用。 hello 甚至从未被打印出来,即使我注释掉 for 循环中的其他行 - for line in pv.stderr 正在阻塞,我不知道为什么。它永远不会解锁,所以即使进程完成,程序仍然卡住 - 我必须杀死它。

我做错了什么导致 for line in pv.stderr 阻塞?

When shell=Trueargs[0]是要执行的命令,args[1:]是传递给sh的参数。您希望将 -prestore_filepath 传递给 pv 而不是 sh。所以使用shell=False。您的另一个 subprocess.Popen 电话也是如此。

由于 shell=Truepv 未收到任何参数,因此挂起,因为它仍在等待文件名。所以再次,解决方案是使用 shell=False.

另请注意,当 replacing a shell pipeline 时,您应该关闭第一个进程的 stdout,以允许它在第二个进程存在的情况下接收 SIGPIPE。这允许一些程序(那些处理 SIGPIPE 的程序)在管道损坏时更优雅地退出。

pv = subprocess.Popen(
    ["pv", "-f", restore_filepath],
    shell=False,  # optional, since this is the default
    bufsize=1,
    stderr=subprocess.PIPE,
    stdout=subprocess.PIPE,
    universal_newlines=True,
)
mysql = subprocess.Popen(
    ["mysql",
     "-u{}".format(db_user),
     "-p{}".format(db_pass),
     db_name],
    shell=False,
    stdout=subprocess.PIPE,
    stderr=subprocess.DEVNULL,
    stdin=pv.stdout,
)
pv.stdout.close() # Allow pv to receive a SIGPIPE if mysql exits. 
for line in pv.stderr:
    print("hello")
    sys.stdout.write("\r" + line.rstrip("\n"))
    sys.stdout.flush()