本文目录导读:

使用 PID 文件(最常用)
#!/bin/bash
# 单实例运行 - PID文件方式
APP_NAME="myapp"
PID_FILE="/var/run/${APP_NAME}.pid"
# 检查是否已有实例运行
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if kill -0 "$PID" 2>/dev/null; then
echo "错误: 程序已在运行 (PID: $PID)"
exit 1
else
# 清理过时的PID文件
rm -f "$PID_FILE"
fi
fi
# 创建PID文件
echo $$ > "$PID_FILE"
# 清理函数
cleanup() {
rm -f "$PID_FILE"
exit 0
}
trap cleanup EXIT
# 主要业务逻辑
echo "程序开始运行 (PID: $$)"
while true; do
# 你的业务代码
echo "运行中..."
sleep 5
done
使用文件锁(flock)
#!/bin/bash
# 单实例运行 - flock文件锁方式
LOCK_FILE="/tmp/myapp.lock"
# 尝试获取锁
exec 200>"$LOCK_FILE"
if ! flock -n 200; then
echo "错误: 程序已在运行"
exit 1
fi
echo "程序开始运行 (PID: $$)"
# 主要业务逻辑
trap 'echo "程序退出"; exit 0' INT TERM
while true; do
echo "运行中..."
sleep 5
done
使用 mkdir 原子操作
#!/bin/bash
# 单实例运行 - mkdir原子操作方式
LOCK_DIR="/tmp/myapp.lockdir"
# 尝试创建锁目录(原子操作)
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
echo "错误: 程序已在运行"
exit 1
fi
# 清理函数
cleanup() {
rm -rf "$LOCK_DIR"
exit 0
}
trap cleanup EXIT
echo "程序开始运行 (PID: $$)"
# 主要业务逻辑
trap 'echo "程序退出"' INT TERM
while true; do
echo "运行中..."
sleep 5
done
使用 ps 命令检查进程
#!/bin/bash
# 单实例运行 - ps命令检查
APP_NAME="myapp"
PID_FILE="/tmp/${APP_NAME}.pid"
# 检查是否已有实例
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
# 检查进程是否存在且确实是我们的程序
if ps -p "$PID" -o comm= | grep -q "$APP_NAME" 2>/dev/null; then
echo "错误: 程序已在运行 (PID: $PID)"
exit 1
fi
fi
# 保存PID
echo $$ > "$PID_FILE"
# 程序主逻辑
echo "程序开始运行 (PID: $$)"
# 你的业务代码
使用 /proc 文件系统(Linux专用)
#!/bin/bash
# 单实例运行 - /proc文件系统方式
LOCK_FILE="/tmp/myapp.pid"
# 检查并记录PID
if [ -f "$LOCK_FILE" ]; then
OLD_PID=$(cat "$LOCK_FILE")
# 检查/proc中进程是否存在
if [ -d "/proc/$OLD_PID" ]; then
echo "错误: 程序已在运行 (PID: $OLD_PID)"
exit 1
fi
fi
echo $$ > "$LOCK_FILE"
# 清理
cleanup() {
rm -f "$LOCK_FILE"
exit 0
}
trap cleanup EXIT
# 主程序
echo "程序开始运行 (PID: $$)"
推荐使用方式
对于简单脚本,推荐使用 flock 方式,因为它:
- 原子操作,安全可靠
- 自动清理锁文件(进程退出时)
- 跨平台性好
#!/bin/bash
# 推荐的单实例脚本模板
LOCK_FILE="/tmp/$(basename "$0").lock"
exec 200>"$LOCK_FILE"
if ! flock -n 200; then
echo "错误: 脚本已在运行"
exit 1
fi
echo "脚本开始执行 (PID: $$)"
# 你的业务逻辑
trap 'echo "脚本退出"' EXIT
# ...
注意事项
- PID文件位置:使用
/var/run/需要root权限,普通用户用/tmp/ - 锁文件清理:确保在脚本退出时清理锁文件
- 信号处理:正确处理 SIGINT、SIGTERM 等信号
- 权限控制:多用户环境下注意锁文件权限
- 性能考虑:频繁检查PID可能影响性能
选择哪种方式取决于你的具体需求和运行环境。