有什么快速而简单的方法可以确保在给定时间内只有一个shell脚本实例在运行?
当前回答
使用flock(1)在文件描述符上创建一个独占作用域锁。通过这种方式,您甚至可以同步脚本的不同部分。
#!/bin/bash
(
# Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
flock -x -w 10 200 || exit 1
# Do stuff
) 200>/var/lock/.myscript.exclusivelock
这确保(和)之间的代码一次只由一个进程运行,并且该进程不会为锁等待太长时间。
注意:这个特殊的命令是util-linux的一部分。如果您运行的是Linux以外的操作系统,那么它可能不可用,也可能不可用。
其他回答
下面是一个使用锁文件并将PID回显到锁文件中的实现。如果进程在删除pidfile之前被杀死,这可以起到保护作用:
LOCKFILE=/tmp/lock.txt
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}
# do stuff
sleep 1000
rm -f ${LOCKFILE}
这里的技巧是kill -0,它不传递任何信号,只是检查具有给定PID的进程是否存在。此外,调用trap将确保即使进程被杀死(kill -9除外),锁文件也会被移除。
if [ 1 -ne $(/bin/fuser "$0" 2>/dev/null | wc -w) ]; then
exit 1
fi
下面这一行的回答来自一个与Ask Ubuntu问答相关的人:
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
# This is useful boilerplate code for shell scripts. Put it at the top of
# the shell script you want to lock and it'll automatically lock itself on
# the first run. If the env var $FLOCKER is not set to the shell script
# that is being run, then execute flock and grab an exclusive non-blocking
# lock (using the script itself as the lock file) before re-execing itself
# with the right arguments. It also sets the FLOCKER env var to the right
# value so it doesn't run again.
这将工作,如果你的脚本名称是唯一的:
#!/bin/bash
if [ $(pgrep -c $(basename $0)) -gt 1 ]; then
echo $(basename $0) is already running
exit 0
fi
如果scriptname不是唯一的,这在大多数linux发行版上都有效:
#!/bin/bash
exec 9>/tmp/my_lock_file
if ! flock -n 9 ; then
echo "another instance of this script is already running";
exit 1
fi
来源:http://mywiki.wooledge.org/BashFAQ/045
如果您不想或不能使用flock(例如,您没有使用共享文件系统),请考虑使用外部服务,如lockable。
它暴露了咨询锁原语,就像flock一样。特别地,你可以通过以下方式获取锁:
https://lockable.dev/api/acquire/my-lock-name
然后通过
https://lockable.dev/api/release/my-lock-name
通过将脚本执行与锁获取和释放结合在一起,您可以确保在任何给定时间只有一个流程实例在运行。