调用在ssh上创建子进程的Python脚本时出现挂起问题

4
我有一堆脚本,用于在多台服务器上启动类似的进程。我想将它们压缩成一个名为“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
3个回答

0

不要在使用subprocess时与shlex一起调用。它不会做你期望的事情。相反,给subprocess一个Python命令列表,例如

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

如果从ssh启动脚本与直接调用脚本有何影响?当直接调用脚本时,脚本可以正常工作。 - dmcauslan

0

当你执行以下操作时:

ssh some_host remote_command remote_cmd_param

如果你想让ssh在remote_command完成之前返回控制权,那么它不会是正常的。如果你想要这样做,你需要在结尾处添加&将其发送到后台。

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

ssh remote_host mc # or any other command using terminal

START脚本会输出一些调试信息,使用print打印到标准输出STDOUT。当我直接调用脚本时,程序会显示这些信息并退出。但是当我通过ssh调用脚本时,只有在子进程终止后才会打印出这些信息。子进程本身会将其他数据记录到自己的stdout中(在Popen调用中明确设置)。 - dmcauslan

0

你应该把这个放在START_APP_A里面

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

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

请注意,如果您需要在APP_A运行时检查此输出,则需要更改APP_A,使其在打印后刷新stdout,否则更改stdout为无缓冲模式。


“stdout=open(file_out, 'a+'), stderr=subprocess.STDOUT”已经重定向IO了吗? - dmcauslan
也许它可以,也许不行。当你用一个shell脚本包装它时,它可以工作,那为什么不直接使用shell呢?此外,我不清楚哪些部分是在本地运行的,哪些部分是在远程运行的。你忽略了stdin,这可能很重要,也可能不重要。无论如何,这一行shell脚本将与任何语言编写的应用程序一起工作,以便在通过ssh连接到的远程服务器上运行它。阅读nohup的man页面以了解更多信息。 - Michael Dillon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接