调用通过 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等,脚本可能会创建子进程执行命令)