如何为Shell脚本添加逻辑,杀死旧进程避免多实例运行?
解决nohup启动脚本重复运行的问题
方案一:使用PID文件(推荐)
这种方法通过记录脚本的进程ID到文件,启动时校验文件中的PID是否对应正在运行的目标脚本进程,确保同一时间仅一个实例运行,可靠性更高。
修改后的脚本如下:
#!/bin/sh # 定义PID文件路径,可放在/tmp或脚本同目录 PID_FILE="/tmp/my_script.pid" # 检查PID文件是否存在 if [ -f "$PID_FILE" ]; then OLD_PID=$(cat "$PID_FILE") # 验证PID对应的进程是否存在且为当前脚本 if ps -p "$OLD_PID" -o cmd= | grep -q "$0"; then echo "发现已有进程在运行(PID: $OLD_PID),正在终止..." kill "$OLD_PID" # 等待进程终止,可选 sleep 2 # 若进程未正常终止,强制杀死 if ps -p "$OLD_PID" > /dev/null; then kill -9 "$OLD_PID" fi fi rm -f "$PID_FILE" fi # 将当前脚本PID写入文件 echo $$ > "$PID_FILE" # 脚本退出时自动清理PID文件,避免残留无效记录 trap 'rm -f "$PID_FILE"; exit' INT TERM EXIT # 原脚本逻辑 i=0 while true do echo $i ((i++)) sleep 1 done
关键说明:
$$表示当前脚本的进程IDtrap命令捕获退出信号,确保脚本无论正常结束还是被强制终止,都能删除PID文件- 额外校验进程命令行,避免PID复用导致误杀其他无关进程
方案二:通过ps命令过滤并杀死旧进程
如果不想依赖PID文件,可直接通过ps命令匹配当前脚本的运行进程,排除自身后清理旧进程。
修改后的脚本:
#!/bin/sh # 获取脚本短文件名,避免路径干扰匹配结果 SCRIPT_NAME=$(basename "$0") # 查找所有运行中的当前脚本进程,排除grep自身和当前执行的进程 OLD_PIDS=$(ps -ef | grep "$SCRIPT_NAME" | grep -v grep | grep -v $$ | awk '{print $2}') if [ -n "$OLD_PIDS" ]; then echo "发现已有进程在运行:$OLD_PIDS,正在终止..." kill $OLD_PIDS # 可选:强制清理未终止的进程 sleep 2 for PID in $OLD_PIDS; do if ps -p "$PID" > /dev/null; then kill -9 "$PID" fi done fi # 原脚本逻辑 i=0 while true do echo $i ((i++)) sleep 1 done
关键说明:
- 多次
grep过滤是为了排除grep自身进程和当前正在启动的脚本进程,避免误杀 - 该方法依赖进程命令行的匹配,若存在同名脚本可能出现误杀,不如PID文件方案可靠
注意事项
- 两种方案均仅针对当前脚本的进程操作,不会影响其他运行的Shell脚本
- 脚本中的
sleep是子进程,杀死脚本的父进程后,子进程会被系统接管并自动终止,无需单独处理
内容的提问来源于stack exchange,提问作者lucky1928
相关产品推荐
相关产品推荐

