Shell脚本在Java失败时未记录退出状态

3

我正在尝试编写一个 shell 脚本,记录 Java 程序的退出状态。该脚本应该简单地启动一个 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作为$?,表示它已经通过了。
我做错了什么?有更好的方法来检测应用程序是否启动失败吗?
谢谢!

1
你想让应用在后台运行,但同时又等待它的状态?这不是违背后台任务的初衷吗? - zapl
1
我想知道的是应用程序是否在启动时失败。如果是前者,我的脚本将备份该应用程序并回滚到以前的版本。不过这还远着呢。我只需要查看应用程序是否能够正常启动。也许“退出状态”不是正确的术语。 - Seanimus
4
在什么时候应该检查状态?你可以等待进程结束(在我看来,这意味着你不需要后台进程),或者在某个更或者更少随机的时间点进行检查,因为应用程序失败需要一些时间(但仍未定义)。你可以定期检查进程是否仍在运行,我认为这大致是系统守护进程采取的方法。 - zapl
1
一个应用程序在退出之前没有“退出代码”,只有等待应用程序退出后才能看到该退出代码。所以,正如zapl所说,如果你不想等待,那么你需要定期检查你的应用程序是否仍然存活。(如果你知道你的应用程序需要花费X时间来正确启动或死亡,那么你可以在那个时间点之后只检查一次。但是,更可能的情况是,你不知道这一点,那么你就需要一直检查,直到它可能死亡或者你不再关心为止。 - Etan Reisner
@Seanimus,你还有什么不清楚的吗? - fukanchik
现在事情清楚了。我想我对等待命令的目的感到困惑。我将编写一个脚本定期检查我的应用程序,并在其未运行时重新启动它。谢谢你的帮助! - Seanimus
1个回答

3

等等!你正在记录wait的退出状态!

这就是为什么你的脚本会出现意外结果的原因。查看bash的man页面(wait是bash内置命令,所以需要阅读bash手册):

wait [-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应用程序非零退出代码。

我可以想象出许多其他原因来取消部署,其中许多原因不会导致非零退出代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接