让shell脚本实现单例运行的方法--富人靠科技穷人靠变异张伟靠过敏
Posted 一碗虾酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了让shell脚本实现单例运行的方法--富人靠科技穷人靠变异张伟靠过敏相关的知识,希望对你有一定的参考价值。
在一些工作场景中,常常会定期执行一些脚本来进行一些动作处理。
比如需要在每小时定时执行一个脚本来将本地的内容打包发送到服务器上,那么我们就可以在crontab下增加自己的脚本。
但有一种情况需要考虑到的是,如果五点开始干活的一个脚本,干到六点还没有干完。而在六点的时候,又定时启动了一次脚本,那么这两个脚本干的活其实是一样的,这样肯定会造成冲突。而我们期望的是每一次脚本的运行都是独立的不会发生运行冲突的。所以,保证脚本运行行在单例模式下是一些场景的必要设计。
单例模式,在设计模式中指的是在程序运行中一个类要保证只有一个实例。又比如一些常见的Windows软件,都需要保证只能开启一个窗口,这就是底层设计模式在界面上的表现。从上面可以知道,在任何开发场景下,都有对程序运行在单例的需求。即使一个小小的脚本也不例外。而加深对单例模式的了解,能够方便一些诡异BUG的排查,比如当脚本发生了不是你预期执行的情况,你就多了一个排查方向,是否是脚本没有单例运行导致。
对脚本的单例设计其实很简单,一种最简单的方法是在脚本运行的过程中对一个flag文件尝试加锁,加锁成功则执行,若加锁失败则代表有脚本在执行,保持单例退出。
还有一种就是在程序运行过程中touch一个flag,flag存在即脚本在运行。这样来保证每次都只有一个脚本在运行。
而今天反而想讨论一下,对于每一个执行的脚本都有自己的进程号,有的方法尝试通过同一脚本程序名与进程号唯一作为单例的判断标准。
(环境是mac OS,所以和linux不同的是并没有/proc文件夹可以查看对应的进程id)
常见的方法是
#如果脚本正在执行,则退出
function keep_singleton()
{
local tmpfile="/tmp/cus_log_report$$"
ps -aux | grep "cus_log_report.sh" | grep -v $$ | grep -v grep | grep -v 'sh -c' | awk '{print $2}' > ${tmpfile}
local processes=`cat ${tmpfile}`
rm -rf ${tmpfile}
if [ "${processes}""empty" != "empty" ]
then
echo "already a script running"
exit 1
fi
}
keep_singleton
看一个小demo的运行情况,让我们看看这种运行情况是否可靠。
我在这个脚本中,过滤排除了自己的进程号和grep指令,但是可以看到最终呈现的是一个进程号为 21853 的进程,但是在前台ps的时候可以看到,并没有这个进程,而是可以看到目前脚本进程21852的进程。
这个21853进程其实是该脚本执行过程中,派生出来的子进程,那这样的话,其实一个脚本对应两个进程号,这种进程号的判断方式就不可取了。
对于脚本的运行,机理其实我并没有了解太深。最近找时间再深入研究一下当运行脚本的过程中到底发生了什么,其实这个脚本可以通过strace进行系统调用的跟踪,你可以看到他在其中派生了子进程。这就是为什么会有两个ID的原因。(这方面我理论不深,请明白银儿指教!)
其实判断单例使用一开始讲的两种方式就可以了,但是要保证的是,你的脚本在系统发生异常或者执行过程中用户ctrl-c了,你要确保即使删除你的flag,不然如果flag在脚本运行失败之后没有及时处理,那么脚本永远不会执行了。大家可以使用trap指令来进行保证。
trap "do some cmd" singal
trap监听信号量,在相应的信号发生时,会去执行cmd。你可以在这里做你的flag清理工作。
下周返校日见! 以上是关于让shell脚本实现单例运行的方法--富人靠科技穷人靠变异张伟靠过敏的主要内容,如果未能解决你的问题,请参考以下文章