有什么快速而简单的方法可以确保在给定时间内只有一个shell脚本实例在运行?
当前回答
如果flock的限制,这已经在这篇文章的其他地方描述过了,对你来说不是问题,那么这应该是有效的:
#!/bin/bash
{
# exit if we are unable to obtain a lock; this would happen if
# the script is already running elsewhere
# note: -x (exclusive) is the default
flock -n 100 || exit
# put commands to run here
sleep 100
} 100>/tmp/myjob.lock
其他回答
当目标是Debian机器时,我发现lockfile-progs包是一个很好的解决方案。Procmail还附带了一个锁文件工具。然而,有时这两种情况我都无法解决。
下面是我的解决方案,它使用mkdir来检测原子性,并使用PID文件来检测过期的锁。这段代码目前在Cygwin安装环境中运行,运行良好。
要使用它,当您需要独占访问某些东西时,只需调用exclusive_lock_require。一个可选的锁名参数允许您在不同的脚本之间共享锁。如果需要更复杂的功能,还有两个较低级别的函数(exclusive_lock_try和exclusive_lock_retry)。
function exclusive_lock_try() # [lockname]
{
local LOCK_NAME="${1:-`basename $0`}"
LOCK_DIR="/tmp/.${LOCK_NAME}.lock"
local LOCK_PID_FILE="${LOCK_DIR}/${LOCK_NAME}.pid"
if [ -e "$LOCK_DIR" ]
then
local LOCK_PID="`cat "$LOCK_PID_FILE" 2> /dev/null`"
if [ ! -z "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2> /dev/null
then
# locked by non-dead process
echo "\"$LOCK_NAME\" lock currently held by PID $LOCK_PID"
return 1
else
# orphaned lock, take it over
( echo $$ > "$LOCK_PID_FILE" ) 2> /dev/null && local LOCK_PID="$$"
fi
fi
if [ "`trap -p EXIT`" != "" ]
then
# already have an EXIT trap
echo "Cannot get lock, already have an EXIT trap"
return 1
fi
if [ "$LOCK_PID" != "$$" ] &&
! ( umask 077 && mkdir "$LOCK_DIR" && umask 177 && echo $$ > "$LOCK_PID_FILE" ) 2> /dev/null
then
local LOCK_PID="`cat "$LOCK_PID_FILE" 2> /dev/null`"
# unable to acquire lock, new process got in first
echo "\"$LOCK_NAME\" lock currently held by PID $LOCK_PID"
return 1
fi
trap "/bin/rm -rf \"$LOCK_DIR\"; exit;" EXIT
return 0 # got lock
}
function exclusive_lock_retry() # [lockname] [retries] [delay]
{
local LOCK_NAME="$1"
local MAX_TRIES="${2:-5}"
local DELAY="${3:-2}"
local TRIES=0
local LOCK_RETVAL
while [ "$TRIES" -lt "$MAX_TRIES" ]
do
if [ "$TRIES" -gt 0 ]
then
sleep "$DELAY"
fi
local TRIES=$(( $TRIES + 1 ))
if [ "$TRIES" -lt "$MAX_TRIES" ]
then
exclusive_lock_try "$LOCK_NAME" > /dev/null
else
exclusive_lock_try "$LOCK_NAME"
fi
LOCK_RETVAL="${PIPESTATUS[0]}"
if [ "$LOCK_RETVAL" -eq 0 ]
then
return 0
fi
done
return "$LOCK_RETVAL"
}
function exclusive_lock_require() # [lockname] [retries] [delay]
{
if ! exclusive_lock_retry "$@"
then
exit 1
fi
}
又快又脏?
#!/bin/sh
if [ -f sometempfile ]
echo "Already running... will now terminate."
exit
else
touch sometempfile
fi
..do what you want here..
rm sometempfile
这个我在任何地方都没有发现,它使用read,我不确切地知道read是否实际上是原子的,但到目前为止它对我来说很有用……它很有趣,因为它只是bash内置的,这是一个进程内实现,你启动locker协进程并使用它的I / O来管理锁,同样可以在进程间完成,只需将目标I / O从locker文件描述符交换到文件系统上的文件描述符(exec 3<>/file && exec 4</file)
## gives locks
locker() {
locked=false
while read l; do
case "$l" in
lock)
if $locked; then
echo false
else
locked=true
echo true
fi
;;
unlock)
if $locked; then
locked=false
echo true
else
echo false
fi
;;
*)
echo false
;;
esac
done
}
## locks
lock() {
local response
echo lock >&${locker[1]}
read -ru ${locker[0]} response
$response && return 0 || return 1
}
## unlocks
unlock() {
local response
echo unlock >&${locker[1]}
read -ru ${locker[0]} response
$response && return 0 || return 1
}
下面这一行的回答来自一个与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.
使用进程的锁更强大,还可以处理不合理的退出。 只要进程在运行,Lock_file就保持打开状态。一旦进程存在,它将被关闭(通过shell)(即使它被杀死)。 我发现这个方法非常有效:
lock_file=/tmp/`basename $0`.lock
if fuser $lock_file > /dev/null 2>&1; then
echo "WARNING: Other instance of $(basename $0) running."
exit 1
fi
exec 3> $lock_file