Shell 脚本在失败时未记录 Java 退出状态
Posted
技术标签:
【中文标题】Shell 脚本在失败时未记录 Java 退出状态【英文标题】:Shell script not recording Java exit status on failure 【发布时间】:2016-05-18 01:00:11 【问题描述】:我正在尝试编写一个记录 Java 程序退出状态的 shell 脚本。该脚本应该简单地启动一个 Java 应用程序,如果 Java 应用程序由于某种原因没有运行,shell 脚本应该检测到这一点并采取缓解措施。
以下是我的脚本:
#!/bin/bash
APPNAME="app"
APPFOLDER=$APPNAME
BACKUP=$APPFOLDER"-backup"
LOGFOLDER=$APPNAME"-log"
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log"
wait
STATUS=$?
if [ $STATUS -eq 0 ]
then
echo "Deployment successful" $?
else
echo "Deployment failed: ... derp" $?
fi
我编写了一个运行良好的简单 Swing GUI。但是,我将它打包为一个 jar,但没有指定入口点。因此,我应该得到错误:
Exception in thread "main" java.lang.NoClassDefFoundError: Demo$1
并且脚本应该检测到应用程序无法启动。
在我尝试使用 & 在后台启动 Java 应用程序之前,所有这些都可以正常工作。每当我这样做时:
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log" &
脚本总是为 $? 返回一个 0,表示它通过了。 我究竟做错了什么?有没有更好的方法来检测应用程序是否启动失败?
谢谢!
【问题讨论】:
您想在后台运行应用程序但还要等待它的状态?这不是违背了后台任务的目的吗? 我想知道的是应用程序是否在启动时失败。在前者的情况下,我的脚本会打包应用程序并在之前的版本中扮演角色。不过那是在路上。我只需要看看应用程序是否可以正常启动。也许“退出状态”是错误的术语。 应该在什么时间点检查状态?您可以等待进程结束(这意味着您不需要后台进程),或者您可以在或多或少的随机点进行检查,因为这需要一些时间(但仍不确定)应用程序失败。您可以定期检查该进程是否仍然存在,我认为这大致是系统守护程序这样做的方法。 应用程序在退出之前没有“退出代码”,只有在等待应用程序退出时才能看到该退出代码。因此,正如 zapl 所说,如果您不想等待,那么您可以定期检查您的应用程序以查看它是否仍然存在。 (如果您知道您的应用程序需要X
长时间才能正确启动或死机,那么您可以在该点之后检查一次。但是,更有可能的是,您不知道,那么您只需继续检查 as只要它可能会死或直到你停止关心。
@Seanimus 有什么不清楚的地方吗?
【参考方案1】:
等等!你正在记录wait
的退出状态!
这就是您在脚本中看到意外结果的原因。查看 bash 的手册页(wait
是 bash 内置的,因此您需要阅读 bash 手册):
等待 [-n] [n ...]
等待每个指定子进程并返回其终止状态。每个n可能是一个进程ID...如果n没有给出,则等待所有当前活动的子进程,返回状态为零(!)。如果 n 指定了一个不存在的进程或作业,则返回状态为 127。否则,返回状态为最后一个进程的退出状态……等待。
由于您尚未指定 n
(要等待的子 pid),因此根据规范,返回状态为 零。
另一个问题是:你真的需要wait
。
如果您不需要在后台运行您的应用程序,那么只需执行以下操作:
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log"
STATUS=$?
唯一的区别是我删除了不必要的wait
。
如果由于某种原因您需要在后台运行您的应用程序并稍后读取退出状态,那么您需要等待该 pid。要找出最后一个后台进程的pid,请使用特殊变量$!
:
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log" &
CHILDPID=$!
wait "$CHILDPID"
STATUS=$?
以下是其工作原理的简短示例:
user@s:~$ (sleep 10 && exit 42)&
[1] 27792
user@s:~$ wait "$!"
[1]+ Exit 42 ( sleep 10 && exit 42 )
user@s:~$ echo $?
42
我想知道的是应用程序是否在启动时失败。在前者的情况下,我的脚本会打包应用程序并在之前的版本中扮演角色。 这个目的太模糊了。您是否只对缺少的依赖项感兴趣?
我认为没有一种简单的方法可以区分 JRE 非零退出代码和 Java 应用程序非零退出代码。
我可以想象许多其他展开部署的原因,其中许多不会导致非零退出代码。
【讨论】:
以上是关于Shell 脚本在失败时未记录 Java 退出状态的主要内容,如果未能解决你的问题,请参考以下文章