Python子进程.check_call vs .check_output

时间:2016-03-23 03:56:42

标签: python bash ssh subprocess

我的python脚本(python 3.4.3)通过子进程调用bash脚本:

import subprocess as sp
res = sp.check_output("bashscript", shell=True)

bashscript 包含以下行:

ssh -MNf somehost

打开与某个远程主机的共享主连接,以允许一些后续操作。

执行python脚本时,它会提示ssh行的密码,但是在输入密码后它会阻塞,并且永远不会返回。当我按ctrl-C终止脚本时,我看到连接已正确建立(因此ssh行已成功执行)。

使用check_call代替check_output时,我没有遇到此阻止问题,但check_call未检索到stdout。我想了解导致check_output阻止行为的确切原因,可能与ssh -MNf的某些微妙之处有关。

1 个答案:

答案 0 :(得分:37)

只要check_call()进程退出而不等待后代进程,

/bin/sh就会返回。

check_output()等待直到读取所有输出。如果ssh继承了管道,那么check_output()将一直等到它退出(直到它关闭其继承的管道结束)。

check_call()代码示例:

#!/usr/bin/env python
import subprocess
import sys
import time

start = time.time()
cmd = sys.executable + " -c 'import time; time.sleep(2)' &"
subprocess.check_call(cmd, shell=True)
assert (time.time() - start) < 1

未读取输出; check_call()立即返回,无需等待孙子背景python进程。

check_call()只是Popen().wait()Popen()启动外部进程并立即返回,而不等待它退出。 .wait()收集进程的退出状态 - 它不等待其他(孙子)进程。

如果输出被读取(它被重定向并且是孙子python  进程继承stdout管道:

start = time.time()
subprocess.check_output(cmd, shell=True)
assert (time.time() - start) > 2

然后等待,直到继承管道的后台python进程退出。

check_output()调用Popen().communicate()来获取输出。 .communicate()在内部调用.wait(),即check_output()也等待shell退出,check_output()等待EOF。

如果孙子没有继承管道,那么check_output()不会等待它:

start = time.time()
cmd = sys.executable + " -c 'import time; time.sleep(2)' >/dev/null &"
subprocess.check_output(cmd, shell=True)
assert (time.time() - start) < 1

Grandchild的输出重定向到/dev/null,即它不会继承父管道,因此check_output()可能会在不等待的情况下退出。

注意:&最后将孙子python进程放入后台。它在shell=True默认启动cmd.exe的Windows上无效。