maihabunash
maihabunash

Reputation: 1702

Shell scripts and how to avoid running the same script at the same time on a Linux machine

I have Linux centralize server – Linux 5.X.

In some cases on my Linux server the get_hosts.ksh script could be run from some other different hosts.

For example get_hosts.ksh could run on my Linux machine three or more times at the same time.

My question:

Upvotes: 5

Views: 4234

Answers (6)

Neil C. Obremski
Neil C. Obremski

Reputation: 20274

Building on wallenborn's answer I also added a "staleness" check just in case the PID lock file is beyond a certain expected age in seconds.

# prevent simultaneous executions within an hourish
pid_file="$HOME/.harness.pid"
max_stale_seconds=3600
if [ -f $pid_file ]; then
    pid="$(cat "$pid_file")"
    let age_in_seconds="$(date +%s) - $(date -r "$pid_file" +%s)"
    if ps $pid >/dev/null && [ $age_in_seconds -lt $max_stale_seconds ]; then
        exit 1
    fi
fi
echo $$>"$pid_file"
trap "rm -f \"$pid_file\"" SIGSEGV
trap "rm -f \"$pid_file\"" SIGINT

This could be made "smarter" to kill off the other executions should the PID be valid but this would be dangerous. Consider a sudden power failure and reset situation where the PID file contains a number that may now reference a completely different process.

Upvotes: 0

Feriman
Feriman

Reputation: 627

I have a lot of scripts, and using this below code for prevent multiple/simulate run:

PID="/var/scripts/PID.txt" # Temp file
if [ ! -f "$PID" ]; then
    echo $$ > "$PID" # Print actual PID into a file
else
    ps -p $(cat "$PID") > /dev/null && exit || echo $$ > "$PID"
fi

Upvotes: 0

MarcoS
MarcoS

Reputation: 17721

A common solution for your problem on *nix systems is to check for a lock file existence.
Usually lock file contains current process PID.
This is an example ksh script:

#!/bin/ksh

pid="/var/run/get_hosts.pid"
trap "rm -f $pid" SIGSEGV
trap "rm -f $pid" SIGINT

if [ -e $pid ]; then
    exit # pid file exists, another instance is running, so now we politely exit
else
    echo $$ > $pid # pid file doesn't exit, create one and go on
fi

# your normal workflow here...

rm -f $pid # remove pid file just before exiting
exit

UPDATE: Answering to OP comment, I add handling program interruptions and segfaults with trap command.

Upvotes: 6

You might consider using the (optional) lockfile(1) command (provided by procmail package on Debian).

Upvotes: 0

wallenborn
wallenborn

Reputation: 4273

The normal way of doing this is to write the process id into a file. The first thing the script does is check for the existence of the file, read the pid, check if a process with that pid exists, and for extra paranoia points, if that process actually runs the script. If yes, the script exits.

Here's a simple example. The process in question is a binary, and this script makes sure the binary runs only once. This is not exactly what you need, but you should be able to adapt this:

RUNNING=0
PIDFILE=$PATH_TO/var/run/example.pid
if [ -f $PIDFILE ]
then
  PID=`cat $PIDFILE`
  ps -eo pid | grep $PID >/dev/null 2>&1
  if [ $? -eq 0 ]
  then
      RUNNING=1
  fi
fi
if [ $RUNNING -ne 1 ]
then
    run_binary
    PID=$!
    echo $PID > $PIDFILE
fi

This is not very elaborate but should get you on the right track.

Upvotes: 3

clinton3141
clinton3141

Reputation: 4841

You can use a pid file to keep track of when the process is running. At the top of the script, check for the existence of the pid file and if it doesn't exist, create it and run the script, otherwise return.

Some sample code can be seen in this answer to a similar question.

Upvotes: 1

Related Questions