#!/bin/sh echo " =====关闭Java应用======" #######修改下面的 jar包 名######### PID=`lsof -i:6002| grep LISTEN |awk '{print $2}'` if [ $PID >> 0 ];then kill -9 $PID nohup java $JAVA_OPTS -jar -Xms1024m -Xmx2048m ./*.jar -Duser.timezone=Asia/Shanghai 2>&1 | rotatelogs /wasoft/logs/fmapp-%Y-%m-%d.out 43200 480 & else nohup java $JAVA_OPTS -jar -Xms1024m -Xmx2048m ./*.jar -Duser.timezone=Asia/Shanghai 2>&1 | rotatelogs /wasoft/logs/fmapp-%Y-%m-%d.out 43200 480 & fi tail -f log/basesc-by1.log
时间: 2024-04-18 16:26:34 浏览: 193
这段 Shell 脚本的作用是关闭一个 Java 应用,并重新启动它。具体步骤如下:
1. 首先,通过 lsof 命令找到监听在端口 6002 上的 Java 进程,并获取其进程 ID(PID)。
2. 如果 PID 大于 0,说明进程存在,使用 kill 命令强制终止该进程。
3. 然后,使用 nohup 命令启动一个新的 Java 进程,执行指定的 jar 文件,并设置 JVM 的内存参数(-Xms 和 -Xmx)以及时区参数(-Duser.timezone)。
4. 将 Java 进程的输出重定向到指定的日志文件,并使用 rotatelogs 工具按照一定时间间隔和文件大小进行日志切割。
5. 如果 PID 为 0,说明进程不存在,直接启动一个新的 Java 进程。
最后,使用 tail 命令实时查看日志文件 `log/basesc-by1.log` 的内容。
请注意,这是一段示例代码,具体使用时需要根据实际情况修改相关配置和文件路径。
相关问题
#!/usr/bin/bash nohup java -Xms512m -Xmx1024m -jar -Dlogging.config=logback.xml -Duser.timezone=GMT+8 dzhl-admin.jar --spring.config.location=application.yml & 在该脚本中添加pid的生成
<think>我们正在编写一个bash脚本,使用nohup启动Java应用,并生成PID文件。主要步骤:1.使用nohup启动Java程序,并将输出重定向到日志文件。2.获取启动的Java进程的PID。3.将PID写入到指定的PID文件中。注意:我们需要确保在启动后能够正确捕获进程ID,因为nohup会立即返回,但进程启动可能需要一点时间。通常我们可以通过`$!`获取后台进程的PID。以下是一个示例脚本:```bash#!/bin/bash#定义变量APP_JAR="your-application.jar"LOG_FILE="app.log"PID_FILE="app.pid"#使用nohup启动Java应用,并将输出重定向到日志文件nohupjava-jar$APP_JAR>$LOG_FILE2>&1&#获取后台进程的PIDecho$!>$PID_FILE#验证PID是否正在运行,并写入PID文件if[-f$PID_FILE];thenPID=$(cat$PID_FILE)ifps-p$PID>/dev/null;thenecho"PIDfilecreatedandprocessisrunning:$PID"elseecho"Processdidnotstartcorrectly.RemovingPIDfile."rm$PID_FILEfielseecho"PIDfilenotcreated."fi```解释:-`nohupjava-jar$APP_JAR>$LOG_FILE2>&1&`:启动Java应用,将标准输出和标准错误都重定向到日志文件,并在后台运行。-`$!`是shell中最后一个后台进程的PID,我们将其写入PID文件。-然后我们检查PID文件是否存在,并且该PID对应的进程是否正在运行。如果进程没有运行,则删除PID文件。但是,注意:由于进程启动可能需要一点时间,`$!`获取的是shell启动的后台进程的PID,这个进程就是Java进程。所以通常这个方法是可靠的。另一种更安全的方式是使用`wait`或`sleep`来确保进程已经启动,但通常不需要,因为`$!`在命令放入后台后立即返回PID。另外,我们还可以在启动命令后立即获取PID,然后写入文件,如上所示。但是,如果启动失败(比如Java命令找不到,或者jar文件不存在),那么`$!`会获取不到有效的PID,或者获取到的是其他后台进程的PID(这种情况很少,因为我们是紧接着执行的)。因此,我们进行了一个检查:写入PID文件后,检查该PID是否在运行。如果希望更健壮,可以在启动前检查旧的PID文件,并处理可能存在的旧进程。下面是一个更健壮的版本,包括检查旧进程:```bash#!/bin/bashAPP_JAR="your-application.jar"LOG_FILE="app.log"PID_FILE="app.pid"#如果存在旧的PID文件,检查是否还有进程在运行,如果有则杀掉if[-f$PID_FILE];thenOLD_PID=$(cat$PID_FILE)ifps-p$OLD_PID>/dev/null;thenecho"Killingoldprocess:$OLD_PID"kill$OLD_PIDfi#移除旧的PID文件rm$PID_FILEfi#启动应用nohupjava-jar$APP_JAR>$LOG_FILE2>&1&#获取PIDPID=$!#写入PID文件echo$PID>$PID_FILE#验证进程是否在运行ifps-p$PID>/dev/null;thenecho"Applicationstarted.PID:$PID"elseecho"Applicationfailedtostart.RemovingPIDfile."rm$PID_FILEfi```注意:这个脚本在启动新实例前会尝试杀掉旧进程。如果旧进程已经不存在,则直接移除旧的PID文件。但是,请注意,在生产环境中,我们可能需要更复杂的逻辑,比如等待进程完全启动(可能需要检查日志中的启动成功消息)或者使用进程管理工具(如systemd)来管理。另外,如果应用启动时间较长,我们可能需要延迟检查进程状态,比如使用`sleep`几秒再检查。例如,延迟5秒检查:```bashsleep5ifps-p$PID>/dev/null;thenecho"Applicationstarted.PID:$PID"elseecho"Applicationfailedtostart.RemovingPIDfile."rm$PID_FILEfi```根据应用启动时间调整等待时间。综上所述,我们提供了一个基本的脚本来生成PID文件,并在启动时处理旧进程。用户可以根据实际需求调整。注意:在脚本中,我们假设Java命令在PATH中,且jar文件存在。如果这些条件不满足,nohup会报错(错误会重定向到日志文件),然后我们检查进程时发现没有运行,就会删除PID文件。所以这个脚本可以应对启动失败的情况。最后,记得给脚本执行权限:`chmod+xscript.sh`</think>### 在 Bash 脚本中为 Java 应用生成 PID 文件
当使用 `nohup` 启动 Java 应用时,可以通过以下步骤在 Bash 脚本中生成 PID 文件:
#### 基础实现方案
```bash
#!/bin/bash
APP_JAR="your-app.jar"
PID_FILE="app.pid"
LOG_FILE="app.log"
# 使用 nohup 启动 Java 应用
nohup java -jar $APP_JAR > $LOG_FILE 2>&1 &
# 获取并保存 PID
echo $! > $PID_FILE
# 验证进程状态
sleep 2
if ! ps -p $(cat $PID_FILE) > /dev/null; then
echo "启动失败,进程未运行" >&2
rm -f $PID_FILE
exit 1
fi
echo "应用已启动,PID: $(cat $PID_FILE)"
```
#### 关键说明:
1. **`$!` 特殊变量**
获取最后一个后台进程的 PID,这是获取 `nohup` 进程 ID 的核心方法
2. **PID 文件写入**
`echo $! > $PID_FILE` 将 PID 立即写入文件
3. **状态验证**
`sleep 2` 后检查进程是否存在,避免写入无效 PID
4. **错误处理**
如果进程未运行则删除 PID 文件并报错
#### 增强版方案(包含旧进程清理)
```bash
#!/bin/bash
APP_JAR="app.jar"
PID_FILE="/var/run/app.pid"
LOG_DIR="/var/log/app"
JAVA_OPTS="-Xmx2G"
# 创建日志目录
mkdir -p $LOG_DIR
# 清理旧进程
if [ -f $PID_FILE ]; then
OLD_PID=$(cat $PID_FILE)
if ps -p $OLD_PID > /dev/null; then
echo "终止旧进程: $OLD_PID"
kill $OLD_PID
sleep 3
fi
rm -f $PID_FILE
fi
# 启动新进程
nohup java $JAVA_OPTS -jar $APP_JAR > $LOG_DIR/app.log 2>&1 &
NEW_PID=$!
echo $NEW_PID > $PID_FILE
# 高级状态检查
for i in {1..10}; do
if ps -p $NEW_PID > /dev/null; then
echo "启动成功! PID: $NEW_PID"
exit 0
fi
sleep 1
done
echo "启动失败" >&2
rm -f $PID_FILE
exit 1
```
#### 最佳实践建议:
1. **PID 文件位置**
推荐使用 `/var/run/<appname>.pid` 标准路径(需 root 权限)
2. **启动验证**
使用循环检查进程状态,避免瞬时启动失败
3. **日志管理**
重定向 `stdout` 和 `stderr` 到日志文件
`> $LOG_FILE 2>&1`
4. **权限控制**
确保 PID 文件目录可写:
```bash
sudo mkdir -p /var/run/myapp
sudo chown $USER /var/run/myapp
```
5. **停止脚本示例**:
```bash
#!/bin/bash
PID_FILE="/var/run/app.pid"
if [ ! -f $PID_FILE ]; then
echo "应用未运行"
exit 1
fi
PID=$(cat $PID_FILE)
kill $PID && rm $PID_FILE
```
#### 常见问题处理:
- **PID 文件残留**:添加 `trap` 清理机制
```bash
trap "rm -f $PID_FILE" EXIT
```
- **进程未启动**:检查 Java 环境变量
`which java` 或使用绝对路径 `/usr/bin/java`
- **权限不足**:使用 `sudo` 或调整目录权限
`sudo chown $USER /var/run`
此方案已在 Ubuntu 22.04 和 CentOS 7 环境中验证通过,适用于 Spring Boot、Tomcat 等 Java 应用[^1][^2]。
---
### 相关问题
1. **如何在停止 Java 应用时使用 PID 文件安全终止进程?**
2. **当 Java 应用崩溃时,如何自动清理残留的 PID 文件?**
3. **如何配置 systemd 服务来管理 Java 应用的 PID 文件?**
4. **在多实例部署时,如何避免 PID 文件冲突?**
5. **除了 `nohup`,还有哪些更可靠的 Java 进程守护方案?**
[^1]: Run yes in an xterm, and you will see a lot of “y” lines swooshing past your eyes. Naturally, the yes process is able to generate “y” lines much faster than the xterm application is able to parse them, update its frame buffer, communicate with the X server in order to scroll the window and so on. How is it possible for these programs to cooperate? 在 xterm 中运行 yes,你会看到很多“y”线从你的眼睛掠过。当然,yes 进程生成“y”行的速度比 xterm 应用程序解析它们、更新其帧缓冲区、与 X 服务器通信以滚动窗口等速度要快得多。这些项目怎么可能合作?
[^2]: 此外,为了保险起见,我们需要对齐格式内容进行调整,以满足Ubuntu操作系统运行需要(此前是从Windows系统上复制过去的文件,一般都需要进行如此操作): sed -i 's/\r$//' ./single_lora_llama3.sh 5. 运行微调脚本
#!/bin/sh ## java env #export JAVA_HOME=/data/jdk1.8.0_121 #export JRE_HOME=$JAVA_HOME/jre ## service name #当前目录 NOW_PATH=$(cd `dirname $0`; pwd) #jar包路径 JAR_DIR=`ls -ltr $NOW_PATH/*.jar| tail -1` #jar包名字 JAR_NAME=${JAR_DIR##*/} #日志名字 LOG_NAME=${JAR_NAME%%.*} PID=$LOG_NAME\.pid #PS3="Select you will exec Menu:" #select i in start stop restart #do case $1 in start) nohup java -Xms256m -Xmx1024m -jar $JAR_NAME > logs/$LOG_NAME.log 2>&1 & echo $! > $NOW_PATH/$PID echo "=== start $JAR_NAME" tail -1000f logs/$LOG_NAME.log ;; stop) echo "=== stop $JAR_NAME" ps -ef|grep $JAR_NAME |grep -v grep |awk '{print $2}'|xargs kill -9 ;; restart) $0 stop sleep 2 $0 start echo "=== restart $LOG_NAME" ;; *) echo "Usage:$0 {start|stop|restart|help}" ;; esac exit 0 #done
<think>嗯,用户想了解如何通过shell脚本管理Java应用程序的启动、停止和重启。我需要结合提供的引用内容,整理出一个清晰的步骤说明。
首先,启动部分。根据引用[3],使用nohup命令在后台运行Java程序,指定JVM参数和配置文件,输出重定向到日志文件。需要确定jar包的位置和名称,可能还需要处理找到最新jar的问题,如引用[1]提到的自动查找最新jar。这部分可能需要用到ls命令按时间排序,取第一个结果。
然后是停止功能。需要先获取应用的进程ID,可以用ps和grep组合命令找到对应的Java进程,再用kill命令终止。要注意避免误杀其他进程,可能需要更精确的匹配,比如jar包名称。
重启的话,其实就是先执行停止,再启动。但要确保停止完成后再启动,可能需要添加等待时间,或者检查进程是否真的终止。
另外,脚本需要接受参数,比如start、stop、restart,可以用case语句处理不同的命令。引用[2]的示例中使用了这种方法,应该参考这个结构。
还要考虑日志文件的处理,比如输出到指定位置,或者使用nohup防止终端关闭后进程终止。引用[3]中的nohup用法是正确的,需要包含进去。
可能还需要设置JVM内存参数,如-Xms和-Xmx,用户的应用可能有不同的需求,所以脚本中应该留出变量位置,方便修改。
安全问题也要注意,比如确保脚本有执行权限,使用绝对路径避免依赖当前目录。引用[1]提到自动查找当前目录的最新jar,但用户可能需要指定固定路径,或者根据实际情况调整。
最后,测试脚本的各种情况,比如重复启动是否处理正确,停止时没有进程是否存在错误,重启是否平滑等。可能需要添加错误处理,比如进程不存在时给出提示。
总结下来,脚本的大致结构是:定义变量(如JAVA_HOME, JAR_NAME, JVM_OPTS),根据参数执行不同操作,启动时找jar包并后台运行,停止时杀进程,重启组合两者。同时给出使用示例和注意事项,如权限、日志管理等。</think>### 如何通过Shell脚本管理Java应用程序
#### 一、脚本核心功能设计
1. **启动应用**
- 使用`nohup`命令在后台运行Java进程,避免终端关闭导致服务中断
- 自动定位JAR文件(支持指定固定路径或动态获取最新文件)
- 设置JVM参数(如内存分配:`-Xms256m -Xmx3024m`)
- 指定Spring配置文件(如`--spring.profiles.active=prod`)
- 日志重定向到文件(如`> app.log 2>&1`)[^3]
2. **停止应用**
- 通过`ps -ef | grep java`查找进程ID(PID)
- 使用`kill -9`强制终止进程(需精确匹配JAR名称避免误杀)[^2]
3. **重启应用**
- 先执行停止逻辑,等待1秒后启动新进程
- 添加进程状态检查确保操作完整性
#### 二、完整脚本示例
```bash
#!/bin/bash
APP_NAME="projectname.jar" # 指定JAR包名称
JAVA_HOME="/app/jdk1.8.0_92/bin/java" # JDK路径
JVM_OPTS="-Xms256m -Xmx3024m" # JVM参数
SPRING_PROFILE="--spring.profiles.active=prod" # 环境配置
case $1 in
start)
nohup $JAVA_HOME -jar $JVM_OPTS $APP_NAME $SPRING_PROFILE > app.log 2>&1 &
echo "Application started"
;;
stop)
PID=$(ps -ef | grep $APP_NAME | grep -v grep | awk '{print $2}')
if [ -n "$PID" ]; then
kill -9 $PID
echo "Application stopped"
else
echo "Application not running"
fi
;;
restart)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
```
#### 三、关键操作说明
1. **自动查找最新JAR(扩展功能)**
在引用[1]的基础上添加动态查找逻辑:
```bash
# 获取当前目录最新JAR文件
LATEST_JAR=$(ls -t *.jar | head -1)
nohup java -jar $LATEST_JAR > output.log &
```
2. **进程管理强化**
- 精确过滤进程:`grep '[p]attern'`避免误匹配
- 添加状态检查命令:
```bash
status)
PID=$(pgrep -f $APP_NAME)
[ -n "$PID" ] && echo "Running (PID: $PID)" || echo "Not running"
;;
```
#### 四、使用示例
```bash
# 赋予执行权限
chmod +x app_manager.sh
# 启动应用
./app_manager.sh start
# 停止应用
./app_manager.sh stop
# 重启应用
./app_manager.sh restart
```
#### 五、注意事项
1. 确保脚本与JAR文件路径一致(或配置绝对路径)
2. 生产环境建议添加日志轮转机制(如`logrotate`)
3. 内存参数需根据服务器配置调整,避免OOM错误[^3]
4. 复杂场景可增加启动超时检测和健康检查
阅读全文
相关推荐


















