Linux:如何防止同一个shell脚本同时执行?

对于如何防止同一个shell脚本同时执行,以前的常用方法是在脚本执行时,先通过如下命令查找是否有相同的脚本名:

ps -ef | grep -v $$ | grep XXXX.sh

但这种方法有以下几个问题:

1、如果这个脚本正被cat、vi、more、tail等工具或命令打开,会造成误判

2、如果脚本是以./XXXX.sh的形式执行的时候,通过这种方式是查不到脚本名的,只能想到这个正在执行的脚本的进程编号

因此,为了能正确的防止同一个shell脚本的同时执行,一般采用如下2种比较简单的方式:

  • trap Exit
  • flock

一、trap Exit

原理说明:

在shell脚本中,trap Exit会为Exit信号配置一个信号处理器,当执行的脚本因正常执行完成或执行出错而要退出时,会执行信号处理器中指定的命令或函数。

防止脚本同时执行的处理流程:

1、使用一个文件充当锁,用于确定是否有脚本正在执行。

2、当脚本执行时,先判断锁文件是否存在,

若锁文件不存在,则创建这个锁文件,然后继续执行脚本;

若锁文件存在,说明已经有一个脚本正在执行,直接终止当前脚本的执行。
3、当脚本正常执行完成或脚本异常退出时,删除这个锁文件。

使用trap EXIT可以有如下2种形式:

#1

trap 'commands_to_execute_before_exit' EXIT

#2

function some_function(){
  #some commands
}
trap some_function EXIT

二、flock

形式:

flock /path/to/file --command "the_actual_command"

参数说明:

不带参数     排它锁
-s                共享锁
-u                解锁
-n                若未获取到锁,不等待,也不执行命令

三、举例

 比如有一个脚本somework.sh

如果是采用trap Exit的方式,可以在somework.sh脚本的开头添加如下函数查重

checkRepeat() {
	lockFile="task.lock"
	
	if [ -f "${lockFile}" ]
	then
		# 读取lock文件中记录的pid
		anotherPid=$(cat ${lockFile})
		# 获取正在执行的脚本的信息
		procInfo=$(ps -ef | grep "${anotherPid}" | grep -v grep)
		
		echo "another script is running. current pid: $$. another pid: ${anotherPid}. another script info:"
		echo "${procInfo}"
	else
		# 创建lock文件
		touch ${lockFile}
		# 将当前进程编号写入lock文件
		echo $$ > ${lockFile}
		
		# 脚本退出前删除lock文件
		trap "printLog \"remove ${lockFile}\"; rm ${lockFile}" EXIT
	fi
}

checkRepeat

# do something

如果是采用flock的方式,只需要通过如下方式调用somework.sh脚本

flock task.lock ./somework.sh

参考文档

https://linuxsimply.com/bash-scripting-tutorial/process-and-signal-handling/signals-handling/bash-trap/
https://linuxsimply.com/bash-scripting-tutorial/process-and-signal-handling/signals-handling/trap-exit/
https://www.man7.org/linux/man-pages/man1/trap.1p.html
https://www.baeldung.com/linux/file-locking
https://linuxhandbook.com/flock-command/
https://linuxhandbook.com/file-locking/

你可能感兴趣的:(linux,运维,服务器)