SSH连接关闭后Java后台执行Bash脚本失效问题排查
问题原因分析
你的核心问题在于nohup的作用范围不对,加上SSH会话断开时的信号传递机制,导致脚本进程被意外终止。
当你执行nohup su - oracle -c './shortoracle.bash'时,nohup只保护了su进程本身,而su切换到oracle用户后启动的shortoracle.bash及其子进程(比如sqlplus实例)并没有被nohup覆盖。当Java的SSH连接因超时断开时,SSH会话会给关联的进程组发送SIGHUP信号,su进程可能被终止,或者它的子进程因为失去终端关联而自行退出——这就是为什么只有3个连接短暂启动后就停了。
另外,即使nohup生效,若没有正确重定向标准输入、输出和错误流,进程可能因为尝试访问已关闭的终端设备而异常退出,这也是导致脚本无法持续运行的潜在因素。
解决方案
调整你的SSH执行命令,让nohup真正作用于oracle用户下的脚本,同时完成所有流的重定向,确保脚本完全脱离终端运行:
sshconnection.execute("su - oracle -c 'nohup ./shortoracle.bash > /dev/null 2>&1 &'", 2000);
关键调整点:
- 把nohup放到su的命令内部:让oracle用户的shell去执行
nohup启动脚本,这样脚本及其所有子进程都会被nohup保护,不受SSH会话断开的SIGHUP信号影响。 - 重定向所有流到/dev/null:
> /dev/null 2>&1将标准输出和标准错误都丢弃,避免进程因尝试写入已关闭的终端而阻塞或退出;最后的&让脚本在oracle用户的后台运行,确保su命令能立即返回,Java的SSH调用不会被阻塞。
额外优化建议
为了让脚本更健壮,建议修改shortoracle.bash里的sqlplus调用,也加上输出重定向,避免日志积累或意外阻塞:
# 替换runsql函数里的sqlplus调用 echo "INSERT into table_$i (col1) values (CURRENT_TIMESTAMP);" | sqlplus username/password > /dev/null 2>&1 # 同理,创建/删除表的sqlplus调用也可以加上重定向 echo "DROP TABLE table_$i;" | sqlplus username/password > /dev/null 2>&1 echo "CREATE TABLE table_$i (col1 TIMESTAMP WITH TIME ZONE);" | sqlplus username/password > /dev/null 2>&1
这样调整后,Java的SSH连接会在2秒内完成命令发送并断开,而shortoracle.bash会在oracle用户下后台持续运行360秒,完成所有插入操作。
内容的提问来源于stack exchange,提问作者totothegreat
相关产品推荐
相关产品推荐

