unix 中 nohup 命令的退出代码问题

unix 中 nohup 命令的退出代码问题

我一直在试图弄清楚如何捕获 nohup 命令的退出状态,然后根据该状态发送邮件。

下面是我的代码:

if [[ "" !=  "$PID" ]]; then
    echo "killing $PID"
    kill -9 $PID
    nohup java -jar Xyz-port-0.0.1.jar &
    << Exit Code and then send mail if Exit 
      code is 0>>
    else 
    echo "Process doesn't exist"
    fi

答案1

后台作业是总是启动成功:

$ sntaoehu &
[1] 33566
$ bash: sntaoehu: command not found
[1]+  Exit 127                sntaoehu
$ echo $?
0

nohup在命令终止之前,您无法在后台启动 Java 程序并检测其运行是否顺利。nohup如果该命令无法找到或启动java,或者每当 Java 程序终止时,该命令将终止。它并不是nohup在后台运行您的程序。它只是让你的程序忽略任何HUP信号,并会一直挂起,直到你的程序终止,然后它将程序的退出状态返回给调用 shell。

如果作业启动则发送电子邮件失败的,你可以这样做

(
    nohup java -jar Xyz-port-0.0.1.jar
    status=$?
    if [ "$status" -eq 126 ] || [ "$status" -eq 127 ]; then
        # something wrong in launching java
        echo 'nohup failed to run java'
        printf 'nohup exit status is %s\n' "$status"
    elif [ "$status" -ne 0 ]; then
        # the java code returned an error
        echo 'java returned an error'
        printf 'java exit status is %s\n' "$status"
    else
        # everything went well and java exited ok
        echo 'java exited safely'
    fi | mail -s 'java job status report' [email protected]
) &

echo 'started background job'

即,启动一个后台子shell,在其中运行程序,然后测试是否返回126或127。如果找不到命令或无法启动命令,nohup它将执行此操作。java

答案2

像这样的东西将更可靠地捕获进程的退出代码:

父级.sh

...
java -jar Xyz-port-0.0.1.jar > /dev/null & #optionally discard stdout of java
child=$!
wait $child
exit_status=$?
if [[ "$exit_status" -ne 0 ]]; then
    # handle error
else
    #handle success
fi

等待

请注意,对 的调用wait将无限期地阻塞,因此,如果您需要对命令完成的时间设置任意限制,您可以用循环java替换对 的调用,并进行一些手动检查以查看进程是否仍在运行。跑步。这将允许您设置一个看门狗,并在进程挂起时将每个人从池中调用。waitps

诺哈普

如果您需要运行 java 进程并处理其退出代码而不处于活动终端会话中,请调用您的父脚本(上面)而nohup不是java代码。父脚本可以nohup编辑,并且将在没有控制终端的情况下在后台生存,并可靠地进行电子邮件发送或清理。

答案3

问题不一定是nohup命令,而是&命令行末尾的问题。

的手册页bash说:

如果命令由控制运算符 & 终止,则 shell 会在子 shell 的后台执行该命令。 shell 不等待命令完成,返回状态为 0。

从技术上讲,shell 分叉一个子 shell 来执行nohup ...命令,执行脚本的主 shell 立即继续执行脚本中的下一个命令。因此,当主 shell 执行该nohup ... &行之后的行时,nohup 命令可能尚未退出:子 shell 可能正在加载它以供执行。

并且该nohup命令不一定会这样退出:它将信号处理程序设置为忽略 HUP 信号,然后尝试直接执行exec()java ...命令。如果exec()系统调用成功,则进程nohup转变为java 无需fork()创建新进程并退出,因此还没有退出代码可返回。

nohup实际命令返回退出代码的唯一方法是如果java无法找到或执行该命令,或者该nohup命令本身存在内部错误。如果exec()系统调用成功,则退出代码唯一可用的时间是java命令本身结束时。

这也是为什么尝试这样的事情并不能达到你想要的效果:

nohup java -jar Xyz-port-0.0.1.jar &
wait $! 
if [ $? -ne 0 ]; then
    echo "Error in running Java"
fi

如果nohup在后台失败,wait将获取其退出代码并允许对其进行检查;但是如果nohup启动成功java,那么该wait命令将一直等待直到java退出,因为nohupjava都会在同一个进程中相继运行。

您可能想做这样的事情,正如 @datUser 建议的那样:

STARTWAIT=20 #number of seconds to wait after starting the service

nohup java -jar Xyz-port-0.0.1.jar &
NEWPID=$!
for i in $(seq $STARTWAIT); do
    # test if the process still exists
    if ! kill -0 $NEWPID 2>/dev/null; then
        # Process has died: get its exit code, report error, stop waiting
        wait $!
        EXITCODE=$?
        echo "Process died after restart and reported result $EXITCODE" >&2
        break
    fi
    sleep 1
done
if kill -0 $NEWPID; then
    echo "The process was started and is still alive after $STARTWAIT seconds"
    echo "so I guess it's now running correctly"
fi

请注意,我的脚本解决方案有一个固有的弱点:如果nohupped 进程终止,而另一个进程在一秒内收到相同的 PID 号,则该脚本将无法注意到它不再是同一进程。 (但是如果你的 PID 号回收得那么快,你可能会遇到更大的问题。)

为了以最佳方式解决问题,您需要脚本设置某种超时机制,该机制将wait在某个预定时间停止命令,然后在wait()受监视的进程上运行系统调用(这是通过waitshell 命令),因为只有受监视进程的实际父进程才能执行此操作。这在 shell 脚本中实现起来相当棘手。

相关内容