首页 > 解决方案 > 使用 shell 脚本启动远程 (SSH) Java 应用程序不会返回本地提示

问题描述

我见过类似的问题,所有已解决的问题都已解决/不适用。

我在远程机器上有一个启动 Java 应用程序的 bash 脚本。相关行将是:

#!/usr/bin/env bash
...
java -cp /full/path/to/my.jar com.whatever.hi.wassup.MainClassThing \
    --arg-1 /full/path/to/relevant_dir --arg-2 /full/path/to/another_dir &
...
echo started my app
exit 0

我用小脚本做了一堆测试,没有任何问题。我使用相同的方法来启动另一个 Java 应用程序,但没有问题(--daemon如果重要,它是一个带有参数的服务器应用程序)。

在本地机器上,我尝试在本地 bash 脚本中调用远程脚本,如下所示:

#!/usr/bin/env bash
...
ssh remote_host myRemoteScript

我的所有测试和其他 Java 应用程序都返回本地提示。问题是,这个确实启动了远程 Java 应用程序并一直到最后一行,输出“启动我的应用程序”但脚本停在那里,除非我没有本地提示Ctrl+C

在工作的Java应用程序上使用ssh -v我得到这个:

debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 2992, received 7060 bytes, in 24.4 seconds
Bytes per second: sent 122.6, received 289.2
debug1: Exit status 0

然而,在非工作应用程序上,我得到了这个:

debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0
"started my app"

但没有本地提示。我尝试使用nohupand运行相同的命令disown,结果相同。正如所见,命令&在最后。仅在远程脚本中注释掉该行没有问题(并且没有任何用处),所以我认为这与 Java 应用程序本身有关——但进程控制不是由 shell 控制的吗?在远程机器上运行 myRemoteScript 也可以正常工作。

这是一个无密码登录。两台机器都是 RHEL 7.2。

编辑

也试过:

标签: javabashssh

解决方案


您可以重定向 java 进程的标准输入、输出和错误,使其标准输入、输出和错误不连接到远程 SSH 服务器:

java ... < /dev/null > /dev/null 2>&1 &

这应该允许远程服务器立即终止 SSH 会话。

当您要求远程 SSH 服务器调用命令,而您没有为该命令请求 TTY 时,服务器将为子进程的标准输入、输出和错误创建一组管道。OpenSSH 服务器的当前行为似乎不是在远程命令退出时关闭会话。相反,当服务器在处理来自远程进程的标准输出的管道上检测到文件结束条件时,它会关闭会话。

您的远程命令启动的 java 进程正在继承 SSH 服务器的管道作为其标准输入等。SSH 服务器没有在这些管道上获得 EOF 指示,因为仍有一个进程可以访问管道。

您可以通过运行如下命令来测试它:

ssh localhost 'sleep 10 < /dev/null > /dev/null &'

如果 ssh 没有等待sleep完成就立即退出,这意味着您已经让远程 SSH 服务器不等待睡眠。

我自己的测试表明 SSH 服务器正在查看从子进程接收标准输出的管道,所以这就是您必须重定向的全部内容。但是您应该考虑重定向所有三个管道——标准输入、输出和错误——以防 SSH 服务器的行为在未来发生变化。


推荐阅读