我一直在试图弄清楚如何捕获 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
替换对 的调用,并进行一些手动检查以查看进程是否仍在运行。跑步。这将允许您设置一个看门狗,并在进程挂起时将每个人从池中调用。wait
ps
诺哈普
如果您需要运行 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
退出,因为nohup
和java
都会在同一个进程中相继运行。
您可能想做这样的事情,正如 @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
请注意,我的脚本解决方案有一个固有的弱点:如果nohup
ped 进程终止,而另一个进程在一秒内收到相同的 PID 号,则该脚本将无法注意到它不再是同一进程。 (但是如果你的 PID 号回收得那么快,你可能会遇到更大的问题。)
为了以最佳方式解决问题,您需要脚本设置某种超时机制,该机制将wait
在某个预定时间停止命令,然后在wait()
受监视的进程上运行系统调用(这是通过wait
shell 命令),因为只有受监视进程的实际父进程才能执行此操作。这在 shell 脚本中实现起来相当棘手。