How to solve the problem of shell script repeated execution

Time:2021-7-28

brief introduction

Flock is a file lock command, which can ensure safe access to critical resources between processes on Linux system. In shell scripts, it can be used to control the mutual exclusion of logic

Example 1

The existing script a.sh is as follows


#!/bin/bash

echo "[`date +'%Y-%m-%d %H:%M:%S'`] begin pid:$$..."

sleep 10

echo "[`date +'%Y-%m-%d %H:%M:%S'`] end pid:$$..."

It is executed in the terminal (recorded as terminal 1)flock -xn ./f.lock -c ./a.shCommand, the result is as follows


[[email protected] lock_test]$ flock -xn ./f.lock -c ./a.sh 
[2020-12-10 10:10:45] begin pid:5359...
[2020-12-10 10:10:55] end pid:5359...

During the execution of the above command, open another terminal (recorded as terminal 2) and execute the same command. The results are as follows


[[email protected] lock_test]$ flock -xn ./f.lock -c ./a.sh 
[[email protected] lock_test]$ 

The above command flock – xn. / f.lock – C. / a.sh

  • -The X option is an exclusive lock, sometimes called a write lock, which is the default option
  • -The N option is non blocking. If the lock cannot be obtained, it will immediately return failure instead of waiting for the release of the lock
  • -The C option is followed by the command to be executed

In terminal 1, execute the command flock – xn. / f.lock – C. / a.sh to lock the f.lock file and execute the command. / a.sh at the same time. The execution process will last about 10 seconds (sleep 10 statement)

Since the flock – xn. / f.lock – C. / a.sh command in terminal 2 is executed during the command execution of terminal 1, terminal 1 has not released the f.lock file lock at this time, and the – N option is non blocking, terminal 2 will not block and wait for the f.lock file lock, but will return immediately

If terminal 2 executes the flock – X. / f.lock – C. / a.sh command, it will block and wait until terminal 1 releases the f.lock file lock. It will not acquire the f.lock file lock and start executing the. / a.sh command

Example 2

In example 1, the command flock – xn file lock – C. / a.sh needs to be executed every time, and each script that cannot be executed repeatedly must be assigned a file lock. It must also be ensured that different scripts use file locks with different names

Is there any way to implement the functions in example 1 by executing the. / a.sh command?

Answer: Yes

Let’s modify a.sh slightly. The modified content is as follows


#!/bin/bash
   
   
echo "[`date +'%Y-%m-%d %H:%M:%S'`] 1111 pid:$$...MY_LOCK:${MY_LOCK}"
   
[ "${MY_LOCK}" != "$0" ] && exec env MY_LOCK="$0" flock -xn "$0" "$0" "[email protected]"
   
echo "[`date +'%Y-%m-%d %H:%M:%S'`] begin pid:$$...MY_LOCK:${MY_LOCK}"
   
sleep 10
echo "[`date +'%Y-%m-%d %H:%M:%S'`] end pid:$$..."

Terminal 1 executes. / a.sh command, and the output is as follows


[[email protected] lock_test]$ ./a.sh
[2020-12-10 14:11:35] 1111 pid:5944...MY_LOCK:
[2020-12-10 14:11:35] 1111 pid:5946...MY_LOCK:./a.sh
[2020-12-10 14:11:35] begin pid:5946...MY_LOCK:./a.sh
[2020-12-10 14:11:45] end pid:5946...

During the command execution of terminal 1, terminal 2 executes. / a.sh command, and the output is as follows


[[email protected] lock_test]$ ./a.sh
[2020-12-10 14:11:44] 1111 pid:5976...MY_LOCK:
[2020-12-10 14:11:44]

Compared with the original a.sh script, the new a.sh script adds lines 4 and 6

Line 4 is log printing

Line 6 description

$0 is the script name, and the value here is. / a.sh

[email protected] is all the parameters passed into the a.sh script

Exec will execute the commands that follow it in the current process, and the commands that have not been executed in the current script process will not be executed

[ "${MY_LOCK}" != "$0" ]Yes, judge my_ Whether the lock environment variable matches the script name (a.sh)
identical

If different, executeenv MY_LOCK="$0"Command andflock -xn "$0" "$0" "[email protected]"command

env MY_ Lock = “$0” set environment variable my_ The value of lock is the script name

flock -xn "$0" "$0" "[email protected]"Actuallyflock -xn ./a.sh ./a.shUse it as the current script file name

In example 2, after executing the. / a.sh command, when running to line 6, my_ The lock variable is null, so[ "${MY_LOCK}" != "$0" ]The result is true

The exec command will ignore the unexecuted commands, that is, the commands after line 6 in the current shell process will not be executed

Then,exec env MY_LOCK="$0" flock -xn "$0" "$0" "[email protected]"Command, my_ Set the value of the lock variable to the current script name. / a.sh, and execute the flock – xn “$0” “$0” “[email protected]” command. This command will be executed in a new sub shell. / a.sh, so the process ID printed in the subsequent output of the script is different from that at the beginning

At the same time, because env my was executed before flock -xn “$0” “$0” “[email protected]”_ LOCK=”$0″,MY_ The value of the lock variable is set to. / a.sh, so when the flock -xn “$0” “$0” “[email protected]” command re executes the. / a.sh command,
[“${my” in line 6 of the script_ LOCK}” != “$ The result of 0 “] is false, and the commands after exec on line 6 will not be executed. The script will be executed from line 7 to the end. The results output logs on lines 8 and 12 also indicate that the script has been executed

summary

Instance 1 and instance 2 provide two methods to solve the repeated execution of scripts, which are mainly realized by setting file locks with the flock command. The method of instance 2 is simpler, which only needs to be added at the beginning of the script[ "${MY_LOCK}" != "$0" ] && exec env MY_LOCK="$0" flock -xn "$0" "$0" "[email protected]" Statement, the command that calls the script remains unchanged

More options and usage of the flock command can be viewed by man flock

The above is the details of how to solve the problem of repeated execution of shell script. For more information about the problem of repeated execution of shell script, please pay attention to other relevant articles of developeppaer!