tags:

views:

1409

answers:

8

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?

+1  A: 
pgrep -f yourscript >/dev/null && exit
chaos
pkill -0 yourscript would probably be better
iny
+4  A: 

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
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
If using `flock`, lock files are easy to manage -- but yes, using `-f` to test their existence is Evil And Wrong.
Charles Duffy
+2  A: 

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

Example:

if pidof vim > /dev/null
then
    echo "Vim already running"
    exit 1
fi
rodion
This is the best way.
olle
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 Reed
A: 

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
A: 

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
+1  A: 

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
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
+1  A: 

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

lhunath