Shell脚本flock加锁实现单实例运行
转自:https://www.cnblogs.com/jmliao/p/11506690.html
命令简介
NAME
flock - manage locks from shell scripts
SYNOPSIS
flock [options] <file|directory>
flock [options] <file|directory> -c
flock [options]
应用场景
在设置定时任务crontab时,如果脚本不支持单实例运行,当某一次定时任务中脚本运行时间较长,下一次定时任务又会启动一个脚本,会导致出现多个实例。若进程太多,会占用大量的CPU资源,导致机器down掉。
解决方案:通过加锁来实现脚本的单实例运行。
示例
- 脚本内部加锁
#!/bin/bash
{
flock –n 3
[$? –eq 1] && { echo fail; exit}
echo succeed
#Do your task here …
} 3<>mylockfile
首先使用<>打开mylockfile 并定向到文件描述符3,而定向文件描述符是先于命令执行的,因此假如要执行的语句段中需要读写mylockfile文件。例如想获得上一个脚本实例的 pid,并将此次的脚本实例的pid写入mylockfile。此时直接用>打开mylockfile会清空上次存入的内容,而用<打开 mylockfile当它不存在时会导致一个错误。
或者使用下面的方法:
#!/bin/bash
exec 6>mylockfile
flock -xn 6
[$? –eq 1] && { echo fail; exit}
#Do your task here …
flock -u 6
exec 6>$-
- 脚本外加锁
上面的方法中,有一个缺陷是需要使用有一个文件描述符。若这个文件描述符被别的程序占用,再使用的话会有冲突。
* * * * * root /bin/bash flock -xn mylockfile /bin/bash my.sh
这种情况下,脚本执行完成或被kill掉,会自动释放文件的锁。
- 原理
在第2中使用方法中,实际上是启动了两个进程,flock是父进程,my.sh是子进程。当父进程被kill后,my.sh成为了孤儿进程,但是此时仍然保持有mylockfile的锁。再使用flock加锁执行脚本,无法获取到锁,执行失败。
对于后台进程来说,父进程退出后子进程仍然拥有mylockfile的锁。
- 注意点
上面的两种方法都能用来实现shell脚本的加锁,但是有一个问题需要注意,在使用加锁启动的脚本中,若启动了子进程,当父进程退出后,子进程仍然持有锁。例如在my.sh中加入sleep 3600,当kill掉my.sh后,mylockfile仍然会被sleep进程持有锁。