由于某些与本问题无关的原因,我正在通过命令替换在单独的子shell中而不是直接运行Java服务器的Bash脚本,并且在后台运行。意图是让子命令将Java服务器的进程ID作为其标准输出返回。相关代码如下:
launch_daemon()
{
/bin/bash <<EOF
$JAVA_HOME/bin/java $JAVA_OPTS -jar $JAR_FILE daemon $PWD/config/cl.yml <&- &
pid=\$!
echo \${pid} > $PID_FILE
echo \${pid}
EOF
}
daemon_pid=$(launch_daemon)
echo ${daemon_pid} > check.out
问题涉及的Java守护程序在初始化时如果遇到问题,会将错误信息打印到标准错误输出并退出;否则,它将关闭标准输出和标准错误输出,并继续执行。脚本的后面部分(未显示)包含了检查服务器进程是否正在运行的代码。现在来看看问题所在。
每当我检查上述的$PID_FILE文件时,它都包含了正确的进程ID。
但是当我检查check.out文件时,有时它会包含正确的ID,而有时它会在同一行上重复两次进程ID,用一个空格字符隔开,如下所示:
34056 34056
我在上面的脚本中使用变量$daemon_pid来检查服务器是否正在运行。如果该变量包含重复的pid,这将完全打乱测试,并且错误地认为服务器未运行。在我的运行CentOS Linux的服务器上调整脚本(例如插入更多echo语句)似乎会将行为翻转回$daemon_pid仅包含一次进程ID的正确行为,但如果我认为已经修复该问题并将此脚本提交到我的源代码库并进行构建和部署,则会开始看到相同的错误行为。
目前,我通过假设$daemon_pid可能存在问题,并将其传递给awk来解决此问题。
mypid=$(echo ${daemon_pid} | awk '{ gsub(" +.*",""); print $0 }')
那么 $mypid 变量始终包含正确的进程 ID,一切都很好,但不用说我想知道为什么它会这样行事。在你问之前,我已经查找了很多次,但是所涉及的 Java 服务器在关闭标准输出之前并未将其进程 ID 打印到标准输出中。
非常感谢专家的意见。
/bin/bash
在你的java服务器成功分离之前终止,那么java服务器将被杀死。这不会导致重复的pid,但会导致无意义的pid。无论如何,我相信你已经测试过了,但是尝试添加>/dev/null
并进行验证也不会有什么损失。 - ricidaemon_pid
中可能会得到两个PID。我强调这只是猜测;我们无法看到足够的代码来确定是否可能发生这种情况,或者如何可能发生这种情况。 - Jonathan Leffler<<EOF
),它不会认为自己是交互式的,除非您指定了-i
。无论如何,如果它确实打印了该消息,我认为它会进入stderr
。但这仍然是一种可能性。 - rici