用 $$ 获取当前脚本 pid 是最可靠轻量的方式,避免 ps/pgrep 的模糊匹配问题;结合文件锁(如 flock)可实现安全防重启动。

直接用 $$ 就能拿到当前脚本的 PID,这是最可靠、最轻量的方式,不需要调用外部命令,也不会受进程名模糊匹配干扰。
为什么用 $$ 而不是 ps 或 pgrep?
很多脚本误用 ps aux | grep xxx 或 pgrep -f xxx 来查自己 PID,但容易出错:
- grep 自身会出现在结果里,需额外过滤
- 脚本名相同(如多个 deploy.sh)或路径不同(./deploy.sh vs /opt/deploy.sh)会导致匹配失败或误杀
- source 方式执行不产生新进程,根本查不到 PID
- bash -c 启动时进程树嵌套,cmdline 内容不稳定
用 $$ 实现防重启动的核心逻辑
关键不是“查 PID”,而是“用 PID 做唯一标识 + 文件锁”:
- 脚本开头立即写入
echo "$$ $0" > /tmp/my_script.pid - 检查该文件是否存在;若存在,读取其中 PID,用
kill -0 $pid 2>/dev/null验证进程是否还在运行且命令名匹配 - 验证失败(进程已死但文件残留)就直接覆盖;验证通过则退出
- 结尾或异常退出前用
trap 'rm -f /tmp/my_script.pid' EXIT确保清理
一个安全可用的最小防重模板
无需依赖外部工具,兼容所有 POSIX shell:
- 定义锁文件路径,比如
PIDFILE="/var/run/$(basename "$0").pid" -
echo "$$ $0" > "$PIDFILE"—— 写入当前 PID 和脚本名 - 用
read pid cmd 读取,再用 <code>kill -0 "$pid" 2>/dev/null && [ "$(basename "$cmd")" = "$(basename "$0")" ]双重校验 - 不满足条件才继续执行,否则
exit 1
进阶建议:配合 flock 更健壮
如果脚本可能被并发触发(如定时任务撞车),单靠文件检查仍有竞态风险。推荐用 flock:
exec 200>"$PIDFILE"; flock -n 200 || { echo "Already running"; exit 1; }- 文件描述符 200 绑定到锁文件,脚本退出自动释放,无需手动清理
- -n 参数让获取失败时立即退出,避免等待











