10

I have a script that runs every 15 minutes but sometimes if the box is busy it hangs and the next process will start before the first one is finished creating a snowball effect. How can I add a couple lines to the bash script to check to see if something is running first before starting?

Ryan Detzel
  • 5,519
  • 9
  • 37
  • 49
  • See [http://stackoverflow.com/questions/185451/quick-and-dirty-way-to-ensure-only-one-instance-of-a-shell-script-is-running-at-a](http://stackoverflow.com/questions/185451/quick-and-dirty-way-to-ensure-only-one-instance-of-a-shell-script-is-running-at-a). – Rob May 29 '09 at 17:11
  • possible duplicate of [shell script execution check if it is already running or not](http://stackoverflow.com/questions/16807876/shell-script-execution-check-if-it-is-already-running-or-not) – AncientSwordRage May 14 '15 at 10:04

9 Answers9

13

You can use pidof -x if you know the process name, or kill -0 if you know the PID.

Example:

if pidof -x vim > /dev/null
then
    echo "Vim already running"
    exit 1
fi
mmoya
  • 1,901
  • 1
  • 21
  • 30
rodion
  • 6,087
  • 4
  • 24
  • 29
  • 1
    Make sure to use the -x flag if you are checking a script, or you won't get a match, because it will be looking for 'bash' – Nathan Apr 22 '10 at 04:00
5

Why don't set a lock file ?

Something like

yourapp.lock

Just remove it when you process is finished, and check for it before to launch it.

It could be done using

if [ -f yourapp.lock ]; then
echo "The process is already launched, please wait..."
fi
Boris Guéry
  • 47,316
  • 8
  • 52
  • 87
  • 1
    Because correctly managing a lock file, in particular handling the case where a process exited improperly and failed to clear its lock file, takes more than a couple lines in bash. – chaos May 29 '09 at 17:09
  • 1
    If using `flock`, lock files are easy to manage -- but yes, using `-f` to test their existence is Evil And Wrong. – Charles Duffy Oct 04 '09 at 14:28
3

This is how I do it in one of my cron jobs

lockfile=~/myproc.lock
minutes=60
if [ -f "$lockfile" ]
then
  filestr=`find $lockfile -mmin +$minutes -print`
  if [ "$filestr" = "" ]; then
    echo "Lockfile is not older than $minutes minutes! Another $0 running. Exiting ..."
    exit 1
  else
    echo "Lockfile is older than $minutes minutes, ignoring it!"
    rm $lockfile
  fi
fi

echo "Creating lockfile $lockfile"
touch $lockfile

and delete the lock file at the end of the script

echo "Removing lock $lockfile ..."
rm $lockfile
A1g0r1thm
  • 75
  • 1
  • 6
3
pgrep -f yourscript >/dev/null && exit
chaos
  • 122,029
  • 33
  • 303
  • 309
3

In lieu of pidfiles, as long as your script has a uniquely identifiable name you can do something like this:

#!/bin/bash
COMMAND=$0
# exit if I am already running
RUNNING=`ps --no-headers -C${COMMAND} | wc -l`
if [ ${RUNNING} -gt 1 ]; then
  echo "Previous ${COMMAND} is still running."
  exit 1
fi
... rest of script ...
allaryin
  • 376
  • 1
  • 4
  • 3
    I did this and I had to tweak it a little. First, COMMAND includes the full path so unless you run it from the same dir it doesn't work. I hard-coded the name anyway. Second, for some reason ps --no-headers -C${COMMAND} | wc -l always returned 1 with nothing running and since this script is running while it's checking that's another 1 so it always returned 2. I had to change the -gt 1 to -gt 2 and it worked. Thanks. – Ryan Detzel Jun 18 '09 at 16:55
2

I had recently the same question and found from above that kill -0 is best for my case:

echo "Starting process..."
run-process > $OUTPUT &
pid=$!
echo "Process started pid=$pid"
while true; do
    kill -0 $pid 2> /dev/null || { echo "Process exit detected"; break; }
    sleep 1
done
echo "Done."
Ruslan
  • 1,076
  • 10
  • 10
2

For a method that does not suffer from parsing bugs and race conditions, check out:

lhunath
  • 120,288
  • 16
  • 68
  • 77
1

To expand on what @bgy says, the safe atomic way to create a lock file if it doesn't exist yet, and fail if it doesn't, is to create a temp file, then hard link it to the standard lock file. This protects against another process creating the file in between you testing for it and you creating it.

Here is the lock file code from my hourly backup script:

echo $$ > /tmp/lock.$$
if ! ln /tmp/lock.$$ /tmp/lock ; then 
        echo "previous backup in process"
        rm /tmp/lock.$$
        exit
fi

Don't forget to delete both the lock file and the temp file when you're done, even if you exit early through an error.

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
1

Use this script:

FILE="/tmp/my_file"
if [ -f "$FILE" ]; then
   echo "Still running"
   exit
fi
trap EXIT "rm -f $FILE"
touch $FILE

...script here...

This script will create a file and remove it on exit.

0x6adb015
  • 7,473
  • 4
  • 24
  • 38