13

Possible Duplicate:
Quick-and-dirty way to ensure only one instance of a shell script is running at a time

I've set up a cronjob to backup my folders properly which I am quite proud of. However I've found out, by looking at the results from the backups, that my backup script has been called more than once by Crontab, resulting in multiple backups running at the same time.

Is there any way I can ensure that a certain shell script to not run if the very same script already is executing?

2

4 Answers 4

35

A solution without race condition or early exit problems is to use a lock file. The flock utility handles this very well and can be used like this:

flock -n /var/run/your.lockfile -c /your/script 

It will return immediately with a non 0 status if the script is already running.

Sign up to request clarification or add additional context in comments.

Comments

7

The usual and simple way to do this is to put something like:

if [[ -f /tmp/myscript.running ]] ; then exit fi touch /tmp/myscript.running 

at the top of you script and

rm -f /tmp/myscript.running 

at the end, and in trap functions in case it doesn't reach the end.

This still has a few potential problems (such as a race condition at the top) but will do for the vast majority of cases.

7 Comments

this will prevent the script from running if it was even run before.
@unbeli: no it won't, because you remove the sentinel file on exit.
There's a race condition because of the TOCTOU (time of check, time of use) between 'the file does not exist' and 'create the file'. The atomic mechanism is mkdir /tmp/myscript.running 2>/dev/null. If the directory exists, the mkdir will fail, and the kernel ensures that only one of concurrently running mkdir commands (system calls) succeeds.
rm wasn't there when I commented. Anyway, this solution is far from the best.
what if script crashes / gets killed / reboot happens while it's runing? script would never run again. Okay, reboot will clear /tmp, but you get the point.
|
5

A good way without a lock file:

ps | grep $0 | grep -v grep > /var/tmp/$0.pid pids=$(cat /var/tmp/$0.pid | cut -d ' ' -f 1) for pid in $pids do if [ $pid -ne $$ ]; then logprint " $0 is already running. Exiting" exit 7 fi done rm -f /var/tmp/$0.pid 

This does it without a lock file, which is cool. ps into a temp file, scrape the first field (pid #) and look for ourselves. If we find a different one, then somebody's already running. The grep $0 is to shorten the list to just those instances of this program, and the grep -v grep gets rid of the line that is the grep itself:)

1 Comment

It's simpler to use pgrep: pids=$(pgrep $0); for pid in $pids
0

You can use a tmp file.
Named it tmpCronBkp.a, tmpCronBkp.b, tmpCronBkp.c... etc. Releated of yout backup script.

Create it on script start and delete it at the end...

In a while, check if file exist or not and what file exist.

Have you tried this way?

3 Comments

I am not sure if I made myself completely clear, but I want to ensure that my shell script isnt executed again, if it's already called by CRON and active
Let this file hold PID of the started process. So you'll be able to figure out is it running at all.
yes, you can check the tmp file and exit from scrit if file exist!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.