问:
有什么快速简便的方法可以确保在给定的时间内只有一个shell脚本实例在运行?
答:
方法一 使用flock(1)在文件描述符上创建一个独占锁。
代码语言:javascript复制#! /bin/bash
(
# Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
flock -x -w 10 200 || exit 1
# 在这里放置脚本的主逻辑部分
) 200>/var/lock/.myscript.exclusivelock
这样可以确保 ( 和 ) 之间的代码一次只由一个进程运行,并且该进程不会为获取锁而等待太长时间。
flock命令是Linux的文件锁命令,可以通过一个锁文件,来控制在shell中逻辑的互斥性。 flock命令的常见选项包括:
- -s:获取共享锁,有时称为读锁。
- -x:获取独占锁,有时称为写锁。这是默认值。
- -n:获取锁失败时立即返回,而不是等待锁被释放。
- -w:等待锁释放的时间,单位为秒。
方法二 是一个使用锁定文件并将PID回显到其中的实现。
代码语言:javascript复制SCRIPT_NAME=$(basename "$0")
LOCKFILE=/tmp/${SCRIPT_NAME}.lock
if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then
echo "already running"
exit
fi
# make sure the lockfile is removed when we exit and then claim it
trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT
echo $$ > ${LOCKFILE}
# 在这里放置脚本的主逻辑部分
sleep 100
rm -f ${LOCKFILE}
这里的技巧是kill -0,它不传递任何信号,只是检查具有给定PID的进程是否存在。此外,对trap的调用将确保锁定文件被删除,即使你的进程被杀死(kill -9除外)。
参考文档:
- stackoverflow question 185451
- https://www.man7.org/linux/man-pages/man1/flock.1.html
- 如何在Bash中提取文件名和扩展名
相关阅读:
- Bash中$$ $! $# $0 $? $* $@ 等各种符号的含义
- 如何使用bash脚本并行运行多个程序
- 如何从Bash脚本本身中获得其所在的目录
- 如何在Bash中连接字符串变量
- 如何编写bash脚本以便在进程死机时重新启动进程