在编写脚本时,通常有单实例运行的需求;比如某个监控脚本,希望同时间只能有一个脚本进程在运行,避免影响业务或是误判断。
一般的做法是通过ps+grep+wc来判断有几个进程在运行,如果超过一个以上则退出,但此方法不够严谨,一方面grep匹配可能有误判,另一方面可能有两个同时刻启动的可能;
还有做法是在脚本最前面,创建一个文件或目录来标识,脚本退出后再清理这个文件,此方法在脚本运行到一半被kill或重启后,由于未执行清理而导致下次运行时判断会失败,就无法再次运行了;

操作系统提供了原子操作级别的文件锁机制,可以在脚本启动时加锁,退出时解锁,同时脚本被意外中断后,文件锁也会被OS释放以避免无法运行,很好的解决了上面的所有问题。

按上面的思路,分别用perl, bash验证了一下,基本符合预期:
(Bash下,不同flock的命令参数可能有所区别。)

Bash:

#!/bin/bash
# Author: tomzhou(admin.net#163.com)

sFile=$0
rMode=$1

#Setting
lFile="/tmp/monitor.tomzhou.lock"


#Locking
touch "$lFile"
if [ "$rMode" != "-r" ]; then
        flock --timeout=0 "$lFile" "$sFile" -r
     #flock -x -w 0 "$lFile" -c "$sFile -r"
     if [ "$?" -ne "0" ]; then
                      echo "Script is running."
                      exit 1
          fi
          exit 0
fi


echo "doing....."
sleep 10
echo "done"


Perl:

#!/usr/bin/perl
# Author: tomzhou(admin.net#163.com)

use Fcntl ':flock';
use Cwd qw(abs_path);
use File::Basename qw(dirname);

#Setting

#Locking
open my $tmpSelFile,'<',$0 or die "Con't open self:$!";
flock $tmpSelFile, LOCK_EX | LOCK_NB or die("Script is running!");


print("doing\n");
sleep(10);
print("done\n");


#Close file
close($tmpSelFile);

SA | 评论(0) | 引用(0) | 阅读(45485)