首选不需要其他工具的解决方案。
ln -s my.pid .lock
会要求锁定(后跟echo $$ > my.pid
),并且在失败时可以检查存储在其中的PID是否.lock
确实是脚本的活动实例
首选不需要其他工具的解决方案。
ln -s my.pid .lock
会要求锁定(后跟echo $$ > my.pid
),并且在失败时可以检查存储在其中的PID是否.lock
确实是脚本的活动实例
Answers:
几乎像nsg的答案:使用lock 目录。在Linux和Unix和* BSD和许多其他操作系统下,目录创建是原子的。
if mkdir $LOCKDIR
then
# Do important, exclusive stuff
if rmdir $LOCKDIR
then
echo "Victory is mine"
else
echo "Could not remove lock dir" >&2
fi
else
# Handle error condition
...
fi
您可以将锁定sh的PID放在lock目录中的文件中以进行调试,但不要陷入可以检查PID来查看锁定过程是否仍在执行的想法。这条道路上有很多比赛条件。
mkdir
不是在NFS原子(这是不适合我的情况,但我想应该提到的是,如果真)
/tmp
通常不在NFS共享中,因此应该没问题。
rm -rf
用来删除锁目录。rmdir
如果有人(不一定是您)设法将文件添加到目录,将失败。
要添加到布鲁斯Ediger的回答,并启发这个答案,你也应该增加更多的智慧来清理打击脚本终止后卫:
#Remove the lock directory
function cleanup {
if rmdir $LOCKDIR; then
echo "Finished"
else
echo "Failed to remove lock directory '$LOCKDIR'"
exit 1
fi
}
if mkdir $LOCKDIR; then
#Ensure that if we "grabbed a lock", we release it
#Works for SIGTERM and SIGINT(Ctrl-C)
trap "cleanup" EXIT
echo "Acquired lock, running"
# Processing starts here
else
echo "Could not create lock directory '$LOCKDIR'"
exit 1
fi
if ! mkdir "$LOCKDIR"; then handle failure to lock and exit; fi trap and do processing after if-statement
。
这可能太简单了,如果我错了,请纠正我。还ps
不够简单吗?
#!/bin/bash
me="$(basename "$0")";
running=$(ps h -C "$me" | grep -wv $$ | wc -l);
[[ $running > 1 ]] && exit;
# do stuff below this comment
grep -v $$
。真实案例:老- 14532,新的- 1453年,老- 28858,新- 858
grep -v $$
为grep -v "^${$} "
grep -wv "^$$"
(参见编辑)对其进行修复。
正如Marco所述,我将使用一个锁定文件
#!/bin/bash
# Exit if /tmp/lock.file exists
[ -f /tmp/lock.file ] && exit
# Create lock file, sleep 1 sec and verify lock
echo $$ > /tmp/lock.file
sleep 1
[ "x$(cat /tmp/lock.file)" == "x"$$ ] || exit
# Do stuff
sleep 60
# Remove lock file
rm /tmp/lock.file
lsof $0
还不错吗?
$$
锁定文件来减少竞争状况。然后sleep
短时间间隔回读。如果PID仍然是您的PID,则说明您已成功获取该锁。绝对不需要其他工具。
如果要确保脚本的仅一个实例正在运行,请查看:
否则,您可以检查ps
或调用lsof <full-path-of-your-script>
,因为我不会称其为其他工具。
补品:
实际上,我想到了这样做:
for LINE in `lsof -c <your_script> -F p`; do
if [ $$ -gt ${LINE#?} ] ; then
echo "'$0' is already running" 1>&2
exit 1;
fi
done
这样可以确保pid
即使<your_script>
同时分叉并执行多个实例,只有最低的进程仍可以继续运行。
[[(lsof $0 | wc -l) > 2]] && exit
实际上可能已经足够了,或者这也容易产生竞争状况吗?
尽管您要求的解决方案没有其他工具,但这是我最喜欢的使用方式flock
:
#!/bin/sh
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
echo "servus!"
sleep 10
这来自的示例部分man flock
,进一步说明了以下内容:
这对于shell脚本很有用。将其放在要锁定的Shell脚本的顶部,它将在第一次运行时自动锁定自身。如果未将env var $ FLOCKER设置为正在运行的shell脚本,则在使用正确的参数重新执行自身之前,执行flock并获取排他的非阻塞锁(使用脚本本身作为锁定文件)。它还会将FLOCKER env var设置为正确的值,因此不会再次运行。
要考虑的要点:
flock
,如果找不到示例脚本,它将以错误终止另请参阅/programming/185451/quick-and-dirty-way-to-ensure-only-one-instance-of-a-shell-script-is-running-at。
这是Anselmo的Answer的修改版本。这个想法是使用bash脚本本身创建一个只读文件描述符,并flock
用来处理锁。
SCRIPT=`realpath $0` # get absolute path to the script itself
exec 6< "$SCRIPT" # open bash script using file descriptor 6
flock -n 6 || { echo "ERROR: script is already running" && exit 1; } # lock file descriptor 6 OR show error message if script is already running
echo "Run your single instance code here"
与其他所有答案的主要区别在于,此代码不会修改文件系统,占用的内存非常少,并且不需要任何清理,因为一旦脚本结束,文件描述符就会关闭,而与退出状态无关。因此,脚本是成功还是失败都没有关系。
exec 6< "$SCRIPT"
。
我正在使用cksum来检查我的脚本是否确实在运行单个实例,即使更改了filename和file path。
我没有使用陷阱和锁定文件,因为如果服务器突然关闭,我需要在服务器启动后手动删除锁定文件。
注意:grep ps需要第一行中的#!/ bin / bash
#!/bin/bash
checkinstance(){
nprog=0
mysum=$(cksum $0|awk '{print $1}')
for i in `ps -ef |grep /bin/bash|awk '{print $2}'`;do
proc=$(ls -lha /proc/$i/exe 2> /dev/null|grep bash)
if [[ $? -eq 0 ]];then
cmd=$(strings /proc/$i/cmdline|grep -v bash)
if [[ $? -eq 0 ]];then
fsum=$(cksum /proc/$i/cwd/$cmd|awk '{print $1}')
if [[ $mysum -eq $fsum ]];then
nprog=$(($nprog+1))
fi
fi
fi
done
if [[ $nprog -gt 1 ]];then
echo $0 is already running.
exit
fi
}
checkinstance
#--- run your script bellow
echo pass
while true;do sleep 1000;done
或者,您可以在脚本中对cksum进行硬编码,因此,如果您要更改脚本的文件名,路径或内容,就不必再担心了。
#!/bin/bash
mysum=1174212411
checkinstance(){
nprog=0
for i in `ps -ef |grep /bin/bash|awk '{print $2}'`;do
proc=$(ls -lha /proc/$i/exe 2> /dev/null|grep bash)
if [[ $? -eq 0 ]];then
cmd=$(strings /proc/$i/cmdline|grep -v bash)
if [[ $? -eq 0 ]];then
fsum=$(grep mysum /proc/$i/cwd/$cmd|head -1|awk -F= '{print $2}')
if [[ $mysum -eq $fsum ]];then
nprog=$(($nprog+1))
fi
fi
fi
done
if [[ $nprog -gt 1 ]];then
echo $0 is already running.
exit
fi
}
checkinstance
#--- run your script bellow
echo pass
while true;do sleep 1000;done
您可以使用此:https : //github.com/sayanarijit/pidlock
sudo pip install -U pidlock
pidlock -n sleepy_script -c 'sleep 10'
我给你的代码
#!/bin/bash
script_file="$(/bin/readlink -f $0)"
lock_file=${script_file////_}
function executing {
echo "'${script_file}' already executing"
exit 1
}
(
flock -n 9 || executing
sleep 10
) 9> /var/lock/${lock_file}
基于man flock
,仅改进:
executing
我在这里放置sleep 10
,您可以放置所有主要脚本。