调用通过 ssh 创建子进程的 Python 脚本挂起

Posted

技术标签:

【中文标题】调用通过 ssh 创建子进程的 Python 脚本挂起【英文标题】:Calling Python script that creates a subprocess over ssh hangs 【发布时间】:2011-11-26 04:09:27 【问题描述】:

我有一堆脚本用于跨多个服务器启动类似的进程。我想将它们浓缩为一个名为“START”的 Python 脚本,但是当它通过 ssh 运行时会发生一些奇怪的事情。

$ ./START APP_A 按预期工作:APP_A 已启动并开始执行其操作。控制立即返回到控制台(在 APP_A 终止之前)。

$ ssh localhost /path_to/START APP_A 类似的工作:APP_A 已启动并开始执行其操作,但 ssh 不会将任何输出打印到屏幕或将控制权返回到控制台,直到 APP_A 终止。

我认为这是信号或文件句柄的问题,但我不知所措。这是似乎造成问题的 Popen 调用:

sub = subprocess.Popen(shlex.split(cmd), stdout=open(file_out, 'a+'), stderr=subprocess.STDOUT, close_fds=True)
print 'New PID:', sub.pid

我在 RHEL 上使用 Python 2.4.3。

编辑: 包装 Python 脚本似乎可行:

DIR="$( cd "$( dirname "$0" )" && pwd )"
pushd $DIR >> /dev/null
./START $1 &
popd >> /dev/null

【问题讨论】:

【参考方案1】:

不要使用 shlex 与子进程一起调用。 It doesn't do what you expect。相反,给 subprocess 命令的 Python 列表,比如

subprocess.Popen(['/some/program', 'arg1', 'arg2', 'arg3'])

【讨论】:

从 ssh 启动脚本与直接调用它会如何受此影响?该脚本在直接调用时工作正常。【参考方案2】:

当你这样做时:

ssh some_host remote_command remote_cmd_param

那么在 remote_command 完成之前 ssh 没有返回控制权是正常的。如果需要,您需要通过在末尾添加& 将其发送到后台。

ssh 将 remote_command 的标准输出重定向到它的(本地)标准输出。如果您没有看到任何输出,这可能是因为 remote_command 没有将任何内容设置为 stdout,而是尝试将其发送到控制台。这就是你不能这样做的原因:

ssh remote_host mc # or any other command using terminal

【讨论】:

START 脚本会输出一些调试信息,这些信息会使用 print 打印到 STDOUT。当我直接调用脚本时,程序会显示此信息并退出。当我通过 ssh 调用脚本时,它只会在子进程终止后打印信息。子进程本身将其他数据记录到自己的标准输出(在 Popen 调用中明确设置)。【参考方案3】:

你应该把它放在 START_APP_A

nohup /path/to/APP_A >/path/to/log 2>&1 </dev/null &

然后它就会工作,APP_A 的所有输出都将进入一个日志文件,您可以在需要时对其进行检查。

请注意,如果您需要在 APP_A 运行时检查此输出,则需要更改 APP_A 以便它在打印后刷新标准输出,或者将标准输出更改为无缓冲。

【讨论】:

“stdout=open(file_out, 'a+'), stderr=subprocess.STDOUT” 是否已经重定向了 IO? 也许是这样,也许不是。当你用 shell 脚本包装它时,它可以工作,所以为什么不直接使用 shell。此外,我不清楚您在本地运行哪些位以及远程运行哪些位。您错过的一件事是标准输入,它可能重要也可能不重要。在任何情况下,一行 shell 脚本都可以与任何语言的任何应用程序一起使用,以便在您使用 ssh 连接到的远程服务器上运行它。阅读 nohup 的手册页以了解更多信息。

以上是关于调用通过 ssh 创建子进程的 Python 脚本挂起的主要内容,如果未能解决你的问题,请参考以下文章

linux shell脚本执行命令时创建子进程问题(特定的情况,例如后台运行管道分支或子shell等,脚本可能会创建子进程执行命令)

linux shell脚本执行命令时创建子进程问题(特定的情况,例如后台运行管道分支或子shell等,脚本可能会创建子进程执行命令)

python 模块积累-----subprocess

Linux 创建子进程执行任务

multiprocessing模块创建子进程

linux c使用system调用shell脚本