Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent a script from running simultaneously? [duplicate]

What's a quick-and-dirty way to make sure that only one instance of a shell script is running at a given time?

like image 289
raldi Avatar asked Oct 09 '08 00:10

raldi


People also ask

How do I make sure only one instance of a bash script runs?

How to Ensure Only One Instance of a Bash Script Is Running 🏃 Just add the pidof line at the top of your Bash script, and you'll be sure that only one instance of your script can be running at a time.

How do I stop a running script?

If it's running in the foreground, Ctrl-C (Control C) should stop it. Read the documentation on the ps command and familiarize yourself with its options. It's a very useful command.

What does bash command do?

Bash or Shell is a command line tool that is used in open science to efficiently manipulate files and directories.


2 Answers

Use flock(1) to make an exclusive scoped lock a on file descriptor. This way you can even synchronize different parts of the script.

#!/bin/bash  (   # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds   flock -x -w 10 200 || exit 1    # Do stuff  ) 200>/var/lock/.myscript.exclusivelock 

This ensures that code between ( and ) is run only by one process at a time and that the process doesn’t wait too long for a lock.

Caveat: this particular command is a part of util-linux. If you run an operating system other than Linux, it may or may not be available.

like image 97
Alex B Avatar answered Sep 23 '22 07:09

Alex B


Naive approaches that test the existence of "lock files" are flawed.

Why? Because they don't check whether the file exists and create it in a single atomic action. Because of this; there is a race condition that WILL make your attempts at mutual exclusion break.

Instead, you can use mkdir. mkdir creates a directory if it doesn't exist yet, and if it does, it sets an exit code. More importantly, it does all this in a single atomic action making it perfect for this scenario.

if ! mkdir /tmp/myscript.lock 2>/dev/null; then     echo "Myscript is already running." >&2     exit 1 fi 

For all details, see the excellent BashFAQ: http://mywiki.wooledge.org/BashFAQ/045

If you want to take care of stale locks, fuser(1) comes in handy. The only downside here is that the operation takes about a second, so it isn't instant.

Here's a function I wrote once that solves the problem using fuser:

#       mutex file # # Open a mutual exclusion lock on the file, unless another process already owns one. # # If the file is already locked by another process, the operation fails. # This function defines a lock on a file as having a file descriptor open to the file. # This function uses FD 9 to open a lock on the file.  To release the lock, close FD 9: # exec 9>&- # mutex() {     local file=$1 pid pids       exec 9>>"$file"     { pids=$(fuser -f "$file"); } 2>&- 9>&-      for pid in $pids; do         [[ $pid = $$ ]] && continue          exec 9>&-          return 1 # Locked by a pid.     done  } 

You can use it in a script like so:

mutex /var/run/myscript.lock || { echo "Already running." >&2; exit 1; } 

If you don't care about portability (these solutions should work on pretty much any UNIX box), Linux' fuser(1) offers some additional options and there is also flock(1).

like image 37
lhunath Avatar answered Sep 22 '22 07:09

lhunath