Python 子进程 .check_call 与 .check_output

标签 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 不检索标准输出。我想了解导致 check_output 阻塞行为的确切原因,可能与 ssh -MNf 的一些微妙之处有关。

最佳答案

check_call()尽快返回 /bin/sh进程退出而不等待后代进程(假设 shell=True 在你的情况下)。

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 进程继承标准输出管道):

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 的 Windows开始 cmd.exe默认情况下。

关于Python 子进程 .check_call 与 .check_output,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36169571/

相关文章:

python - 循环更新帧时的 LineCollection 动画

python - 刷新 GAE 中的输出?

python - 在Python中的函数中声明全局变量

python - Scrapy中间件 'NoneType'不可迭代

php - 如何将html转换成一行字符串?

bash - [[ $- = *i* ]] 在 bash 中是什么意思?

regex - 纯粹使用 bash 正则表达式压缩工作目录

python - git.exc.GitCommandNotFound : [WinError 5] Access is denied

linux - 我可以从 ssh 命令获得某种类型的返回值吗?

linux - 通过中间机器挂载远程文件系统(sshfs)