i have a bash script that runs daily rsync incremental backups.
my problem is i end up with multipul instances running. im new to bash scripts so im not sure if i have an issue in my script? posted below.
but i have read about a pid lockfile?
could anyone show me how i would go about adding this into my script?
#!/bin/bash
PATH=/usr/lib64/qt- 3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
LinkDest=/home/backup/files/backupdaily/monday
WeekDay=$(date +%A |tr [A-Z] [a-z])
echo "$WeekDay"
case $WeekDay in
monday)
echo "Starting monday's backup"
rsync -avz --delete --exclude backup --exclude virtual_machines /home /home/backup/files/backupdaily/monday --log- file=/usr/local/src/backup/logs/backup_daily.log
;;
tuesday|wednesday|thursday|friday|saturday)
echo "Starting inc backup : $WeekDay"
rsync -avz --exclude backup --exclude virtual_machines --link-dest=$LinkDest /home /home/backup/files/backupdaily/$WeekDay --log- file=/usr/local/src/backup/logs/backup_daily.log
;;
sunday) exit 0
;;
esac
so it looks like this?
#!/bin/bash
PATH=/usr/lib64/qt- 3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
trap "rm -f /tmp/backup_daily_lockfile && exit" SIGINT SIGTERM #Put this on the top to handle CTRL+C or SIGTERM
test -f /tmp/backup_daily_lockfile && exit #before rsync to ensure that the script will not run if there is another one running
LinkDest=/home/backup/files/backupdaily/monday
WeekDay=$(date +%A |tr [A-Z] [a-z])
echo "$WeekDay"
touch /tmp/backup_daily_lockfile #Before the rsync
case $WeekDay in
monday)
echo "Starting monday's backup"
rsync -avz --delete --exclude backup --exclude virtual_machines /home /home/backup/files/backupdaily/monday --log-file=/usr/local/src/backup/logs/backup_daily.log
;;
tuesday|wednesday|thursday|friday|saturday)
echo "Starting inc backup : $WeekDay"
rsync -avz --exclude backup --exclude virtual_machines --link-dest=$LinkDest /home /home/backup/files/backupdaily/$WeekDay --log-file=/usr/local/src/backup/logs/backup_daily.log
;;
sunday) exit 0
;;
rm -f /tmp/backup_daily_lockfile #After the rsync
esac
2 Answers 2
Your proposed solution has a race condition. If two instances are running at approximately the same time, they could both execute the test before either of them gets to the touch. Then they will end up overwriting each others' files after all.
The proper fix is to use an atomic test and set. A common and simple solution is to use a temporary directory instead, and exit if mkdir fails; otherwise, you have the lock.
# Try to grab lock; yield if unsuccessful
mkdir /tmp/backup_daily_lockdir || exit 1
# We have the lock; set up to remove on exit
trap "rmdir /tmp/backup_daily_lockdir" EXIT
# Also run exit trap if interrupted
trap 'exit 127' SIGINT SIGTERM
: the rest of your script here
There are other common solutions, but this has no external dependencies and is very easy to implement and understand.
2 Comments
mv tempfile lockfile - renaming is supposed to be atomic on at least most of the common file systems. It may not be universally guaranteed, though...Add the following to your script:
trap "rm -f /tmp/lockfile && exit" SIGINT SIGTERM #Put this on the top to handle CTRL+C or SIGTERM
test -f /tmp/lockfile && exit #Before rsync to ensure that the script will not run if there is another one running
touch /tmp/lockfile #Before the rsync
rm -f /tmp/lockfile #After the rsync
rename the lock file path/name according to your needs, you can also name it with the current PID using $$ variable.
4 Comments
-f' /usr/local/src/backup/backup_daily_v3.sh: line 30: rm -f /tmp/backup_daily_lockfile #After the rsync'