判断shell脚本是否唯一运行中

判断shell脚本是否唯一运行中

需掌握的知识点

shell中的比较不是使用简单的> = <等,而是用扩展符
-eq //等于  equal
-ne //不等于 no equal
-gt //大于  great than
-lt //小于 less than 
ge  //大于等于  great and equal 注意没有"-"
le //小于等于 less and equal 注意没有"-"

$$  Shell本身的PID(ProcessID)
$!  Shell最后运行的后台Process的PID
$?  最后运行的命令的结束代码(返回值)
$0  Shell本身的文件名
$1  运行过程中手打输入传递给该shell脚本的第一个参数
$2  运行过程中手打输入传递给该shell脚本的第二个参数
$@  传给脚本的所有参数的列表

--判断文件存在
-e filename 如果 filename存在,则为真 
-d filename 如果 filename为目录,则为真 
-f filename 如果 filename为常规文件,则为真 
-L filename 如果 filename为符号链接,则为真 
-r filename 如果 filename可读,则为真 
-w filename 如果 filename可写,则为真 
-x filename 如果 filename可执行,则为真 
-s filename 如果文件长度不为0,则为真 
-h filename 如果文件是软链接,则为真


trap命令:
当bash接收到一个UNIX信号时,运行一个命令或者一个函数。比如脚本运行结束、非正常
退出CTRL+C终止、kill脚本等。trap命令可以在接受到以上信号时编写你要运行的命令。你可以链接多个
信号(列表可以使用kill -l获得),但是为了清理残局,我们只使用其中的三个:INT,TERM和EXIT。
你可以使用-as来让traps恢复到初始状态。

INT Interrupt - 当有人使用Ctrl-C终止脚本时被触发
TERM Terminate - 当有人使用kill杀死脚本进程时被触发
EXIT Exit - 这是一个伪信号,当脚本正常退出或者set -e后因为出错而退出时被触发

trap命令一般使用在文件锁的场景
trap "rm -f ${LOCKFILE}; exit" INT TERM EXI //在以上三个场景时,删除文件锁并且退出脚本。

背景

如果脚本运行卡住或者运行异常没有退出时,继续运行脚本会发生未知的错误。比如脚本启动关闭数据库、应用等场景。所以在脚本运行前加上判断此脚本是否还在运行就显得比较重要了。简单的思路是在脚本运行前段查询当前脚本的进程是否在运行,在运行的话判断为是。简单的脚本如下:

#!/bin/bash
echo $0
ps -ef|grep $0 | grep -v grep 
runCount=`ps -ef|grep $0 | grep -v grep -c`
if [ $runCount -ge 1 ] 
then
    echo -e "example.sh is running,pro_Counts:${runCount}"

fi

运行上述脚本后结果如下:

[root@localhost ~]# ./example.sh 
root      1421 25320  0 15:53 pts/1    00:00:00 /bin/bash ./example.sh
example.sh is running,pro_Counts:2	

可以看到查看进程后过滤后只有一条,但是程序数量显示出来却是2。原因在于,shell脚本中的ps查看example相关进程的命令相当于子进程执行了一次,然后当前脚本也是和example相关的进程,所以会出现两个。

文件锁

使用文件锁的方式实现单进程脚本运行。过程如下:

  • 运行前检查是否有该锁文件,并且文件中的进程正在运行

  • 如果有并且程序正在运行,则已经有实例在运行

  • 否则,无实例,创建锁文件,写入进程id

  • 退出时,删除锁文件

    具体程序如下:

      #!/usr/bin/env bash
      LOCKFILE=/tmp/pid.lock
      if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then  //判断LOCKFILE文件是否存在和检查LOCKFILE文件里的进程PID 是否存在,存在返回0
          echo " $0 is running"
          exit
      fi
      
      # 确保退出时,锁文件被删除
      trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT  //
      #将当前程序进程id写入锁文件
      echo $$ > ${LOCKFILE}
      
      # 做你需要的事情
      sleep 100
      
      # 删除锁文件
      rm -f ${LOCKFILE}
    

    另外运行此程序的话结果如下:

      [root@localhost ~]# cat /tmp/pid.lock 
      7820
      [root@localhost ~]# sh example2.sh 
       example2.sh is running
    

    上述判断脚本可以运行在UNIX下的所有操作系统,比如:Aix等。对于linux 操作系统可以使用flock命令。

flock

在Linux下说到锁文件,这里就不得不提flock命令了。没有前面的一些巧妙处理,我们很多时候会很难删除原先创建的锁文件,比如:

  • 脚本被意外中断,没来得及执行删除
  • 多个脚本产生竞争,导致判断异常,比如前面有一个脚本运行,判断没有锁文件,下一步准备创建,但是另外一个脚本又先创建了,就会导致异常了。

使用flock来完成文件锁脚本如下:

#!/bin/bash
LOCK_FILE=/tmp/test.lock
exec 99>"$LOCK_FILE"
flock -n 99
if [ "$?" != 0 ]; then
    echo "$0 already running"
    exit 1
fi
#脚本要做的其他事情
sleep 1024
  • exec 99>"$LOCK_FILE" 表示创建文件描述符99,指向锁文件,为何是99?110其实也是可以的,只是为了和当前脚本可能打开的文件描述符冲突(例如和0,1,2冲突)。
  • flock -n 99 尝试对该文件描述符加锁,由操作系统保证原子性
  • 一旦flock失败了,我们这里可以退出
  • 而即使锁定了,脚本退出后,也会自动释放

查看flock的man手册,我们发现它还有一个例子是这么做的:

#!/bin/bash
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en  "$0"  "$0"  "$@" || :
#脚本要做的其他事情
sleep 1024

如果${FLOCKER}环境变量没有设置,则尝试将脚本本身加锁,如果加锁成功,则运行当前脚本,(并且带上原有的参数),否则的话静默退出。

总结

判断脚本唯一执行的基本总结到此。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值