3 Commits
1.1 ... 1.2.1

Author SHA1 Message Date
a708ec80ca Add user option
Added a command line option to specify the user performing the backup.
This is useful if running the program with sudo.
2015-11-26 01:03:33 +01:00
f5365fddff Add warning in example configuration 2015-11-25 13:26:57 +01:00
473ee59868 Improve configuration file parsing
The configuration file is now parsed with a simple awk program
which is simpler to understand and maintain
2015-11-25 12:33:49 +01:00
2 changed files with 79 additions and 151 deletions

2
config
View File

@ -1,5 +1,7 @@
#Example config file for my_backup #Example config file for my_backup
# WARNING: Values should NOT be quoted, e.g. use inputs=/some/dir instead of inputs="/some/dir"
#Input directories. Use a comma to separate items #Input directories. Use a comma to separate items
inputs=/home/my_home,/etc inputs=/home/my_home,/etc

View File

@ -15,7 +15,7 @@
#You should have received a copy of the GNU General Public License #You should have received a copy of the GNU General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>. #along with this program. If not, see <http://www.gnu.org/licenses/>.
#Version 1.1 #Version 1.2.1
#Simple backup script. Reads options, sources and destination from a configuration file or standard input #Simple backup script. Reads options, sources and destination from a configuration file or standard input
#Help function #Help function
@ -35,6 +35,8 @@ function help_function {
echo " the backup." echo " the backup."
echo "-k, --keep NUMBER Specify the number of old backups to keep." echo "-k, --keep NUMBER Specify the number of old backups to keep."
echo " Default: keep all." echo " Default: keep all."
echo "-u, --user USER User performing the backup."
echo " Default: current user."
echo "" echo ""
echo "If no option is given, the program uses the default" echo "If no option is given, the program uses the default"
echo "configuration file: $HOME/.simple_backup/config." echo "configuration file: $HOME/.simple_backup/config."
@ -74,156 +76,68 @@ function read_conf {
fi fi
while read line #Create temporary files
do INPUTS=$(mktemp)
#Ignore comments and empty lines EXCLUDE=$(mktemp)
if [[ $line == \#* || $line == "" ]]; then BACKUP=$(mktemp)
continue NKEEP=$(mktemp)
else
#Get option name and values for the current line
var=$(echo "$line" | cut -d"=" -f1)
case "$var" in #Parse the configuration file
#Files/folders to backup awk -v INPUTS="$INPUTS" -v EXCLUDE="$EXCLUDE" -v BACKUP="$BACKUP" \
inputs) -v NKEEP="$NKEEP" -v UHOME="$HOME/" -F '[=,]' \
#Create a temporary file to store inputs '$1=="inputs" { for ( i=2; i<=NF; i++ ) { sub(/^~\//,UHOME,$i); print $i > INPUTS } }
INPUTS=$(mktemp) $1=="backup_dir" { sub(/^~\//,UHOME,$2); print $2 > BACKUP }
tmp=$(echo "$line" | cut -d"=" -f2) $1=="exclude" { for ( i=2; i<=NF; i++ ) { sub(/^~\//,UHOME,$i); print $i > EXCLUDE } }
n=$(echo "$tmp" | awk -F ',' '{print NF}') #Files/folders must be separated with commas $1=="keep" { if ( $2 != NULL ) { print $2 > NKEEP } }' $CONFIG
i=1
#j=1
n_in=0
#Read each input and save it to the INPUTS file BACKUP_DEV=$(cat $BACKUP)
while [[ $i -le $n ]] KEEP=$(cat $NKEEP)
do
input=$(echo "$tmp" | cut -d"," -f$i) rm "$BACKUP"
input=$(echo "$input" | tr -d \"\') rm "$NKEEP"
if [[ "$input" =~ ^~/ ]]; then if [[ -z "$BACKUP_DEV" || ! -d "$BACKUP_DEV" ]]; then
input=$(echo ${input/\~/$HOME}) #If the backup directory is not set or doesn't exist, exit
fi echo "$(date): Backup failed (see errors.log)" >> $HOME/.simple_backup/simple_backup.log
echo "Error: Output folder \"$BACKUP_DEV\" not found" | tee -a $HOME/.simple_backup/errors.log
#If libnotify is installed, show desktop notification that backup failed
! command -v notify-send > /dev/null 2>&1 || DISPLAY=:0.0 notify-send -u low -t 10000 "Backup failed"
if [[ ! -e "$input" ]]; then if [[ -f $HOME/.simple_backup/simple_backup.log.old ]]; then
#Warn the user if an input doesn't exist rm -f $HOME/.simple_backup/simple_backup.log.old
echo "Warning: input \"$input\" not found. Skipping" | tee -a $HOME/.simple_backup/warning.log
else
n_in=$((n_in+1))
fi
echo "$input" >> $INPUTS
i=$((i+1))
done
;;
#Directory where the backup is saved
backup_dir)
BACKUP_DEV=$(echo "$line" | cut -d"=" -f2)
BACKUP_DEV=$(echo "$BACKUP_DEV" | tr -d \"\')
if [[ "$BACKUP_DEV" =~ ^~/ ]]; then
BACKUP_DEV=$(echo ${BACKUP_DEV/\~/$HOME})
fi
if [[ -z "$BACKUP_DEV" ]]; then
#If the backup directory is not set, exit
echo "$(date): Backup failed (see errors.log)" >> $HOME/.simple_backup/simple_backup.log
echo "Error: No backup folder set in configuration file" | tee -a $HOME/.simple_backup/errors.log
#If libnotify is installed, show desktop notification that backup failed
! command -v notify-send > /dev/null 2>&1 || DISPLAY=:0.0 notify-send -u low -t 10000 "Backup failed"
if [[ -f $HOME/.simple_backup/simple_backup.log.old ]]; then
rm -f $HOME/.simple_backup/simple_backup.log.old
fi
if [[ -f $HOME/.simple_backup/errors.log.old ]]; then
rm -f $HOME/.simple_backup/errors.log.old
fi
if [[ -f $HOME/.simple_backup/warnings.log.old ]]; then
rm -f $HOME/.simple_backup/warnings.log.old
fi
exit 1
fi
if [[ ! -d "$BACKUP_DEV" ]]; then
#If the backup directory doesn't exist, exit
echo "$(date): Backup failed (see errors.log)" >> $HOME/.simple_backup/simple_backup.log
echo "Error: Output folder \"$BACKUP_DEV\" not found" | tee -a $HOME/.simple_backup/errors.log
#If libnotify is installed, show desktop notification that backup failed
! command -v notify-send > /dev/null 2>&1 || DISPLAY=:0.0 notify-send -u low -t 10000 "Backup failed"
if [[ -f $HOME/.simple_backup/simple_backup.log.old ]]; then
rm -f $HOME/.simple_backup/simple_backup.log.old
fi
if [[ -f $HOME/.simple_backup/errors.log.old ]]; then
rm -f $HOME/.simple_backup/errors.log.old
fi
if [[ -f $HOME/.simple_backup/warnings.log.old ]]; then
rm -f $HOME/.simple_backup/warnings.log.old
fi
exit 1
fi
BACKUP_DIR=$BACKUP_DEV/simple_backup
DATE=$(date +%Y-%m-%d-%H:%M)
#Create the backup subdirectory using date
if [[ ! -d "$BACKUP_DIR" ]]; then
mkdir -p "$BACKUP_DIR/$DATE"
else
#If previous backup(s) exist(s), save link to the last backup
LAST_BACKUP=$(readlink -f "$BACKUP_DIR/last_backup")
mkdir "$BACKUP_DIR/$DATE"
fi
#Set the backup directory variable to the newly created subfolder
BACKUP_DIR="$BACKUP_DIR/$DATE"
;;
#Files/directories/patterns to exclude from backup
exclude)
#Create temp file to store exclude patterns
EXCLUDE=$(mktemp)
temp=$(echo "$line" | cut -d"=" -f2)
i=1
n=$(echo "$temp" | awk -F ',' '{print NF}') #Exclude patterns must be separated by commas
#Read each exclude pattern and save it in the temp file
while [[ $i -le $n ]]
do
var=$(echo "$temp" | cut -d"," -f$i)
var=$(echo "$var" | tr -d \"\')
if [[ "$var" =~ ^~/ ]]; then
var=$(echo ${var/\~/$HOME})
fi
echo "$var" >> $EXCLUDE
i=$((i+1))
done
;;
#Number of old backups to keep
keep)
KEEP=$(echo "$line" | cut -d"=" -f2)
;;
#Unrecognized options
*)
#Skip unrecognised options
echo "$(date): Warning: option \"$var\" not recognised. Skipping" >> $HOME/.simple_backup/warnings.log
;;
esac
fi fi
done<"$CONFIG"
if [[ -f $HOME/.simple_backup/errors.log.old ]]; then
rm -f $HOME/.simple_backup/errors.log.old
fi
if [[ -f $HOME/.simple_backup/warnings.log.old ]]; then
rm -f $HOME/.simple_backup/warnings.log.old
fi
rm "$INPUTS"
rm "$EXCLUDE"
exit 1
fi
BACKUP_DIR=$BACKUP_DEV/simple_backup
DATE=$(date +%Y-%m-%d-%H:%M)
#Create the backup subdirectory using date
if [[ ! -d "$BACKUP_DIR" ]]; then
mkdir -p "$BACKUP_DIR/$DATE"
else
#If previous backup(s) exist(s), save link to the last backup
LAST_BACKUP=$(readlink -f "$BACKUP_DIR/last_backup")
mkdir "$BACKUP_DIR/$DATE"
fi
#Set the backup directory variable to the newly created subfolder
BACKUP_DIR="$BACKUP_DIR/$DATE"
n_in=$(cat $INPUTS | wc -l)
return return
} }
@ -231,6 +145,9 @@ function read_conf {
function parse_options { function parse_options {
i=1 i=1
n_in=0 n_in=0
#Create a temporary file to store inputs
INPUTS=$(mktemp)
#Create temp file to store exclude patterns #Create temp file to store exclude patterns
EXCLUDE=$(mktemp) EXCLUDE=$(mktemp)
@ -254,12 +171,13 @@ function parse_options {
mv -f $HOME/.simple_backup/warnings.log.old $HOME/.simple_backup/warnings.log mv -f $HOME/.simple_backup/warnings.log.old $HOME/.simple_backup/warnings.log
fi fi
rm $INPUTS
rm $EXCLUDE
exit 0 exit 0
;; ;;
-i | --input) -i | --input)
#Create a temporary file to store inputs
INPUTS=$(mktemp)
while [[ "$#" -gt 1 && ! "$2" =~ ^- ]] while [[ "$#" -gt 1 && ! "$2" =~ ^- ]]
do do
@ -354,13 +272,21 @@ function parse_options {
;; ;;
-c | --config) -c | --config)
if [[ -f "$EXCLUDE" ]]; then
rm "$EXCLUDE" rm "$EXCLUDE"
fi rm "$INPUTS"
read_conf "$2" read_conf "$2"
return return
;; ;;
-u | --user)
rm "$EXCLUDE"
rm "$INPUTS"
config="/home/$2/.simple_backup/config"
read_conf "$config"
return
;;
*) *)
echo "$(date): Backup failed (see errors.log)" >> $HOME/.simple_backup/simple_backup.log echo "$(date): Backup failed (see errors.log)" >> $HOME/.simple_backup/simple_backup.log
echo "Error: Option $1 not recognised. Use 'simple-backup -h' to see available options" | tee -a $HOME/.simple_backup/errors.log echo "Error: Option $1 not recognised. Use 'simple-backup -h' to see available options" | tee -a $HOME/.simple_backup/errors.log
@ -496,9 +422,9 @@ if [[ ! -z "$INPUTS" ]]; then
fi fi
if [[ -z "$LAST_BACKUP" ]]; then if [[ -z "$LAST_BACKUP" ]]; then
rsync -acrv -H -X -R --exclude-from="$EXCLUDE" --files-from="$INPUTS" / "$BACKUP_DIR" >> "$HOME/.simple_backup/simple_backup.log" 2>> "$HOME/.simple_backup/errors.log" rsync -acrv -H -X -R --exclude-from="$EXCLUDE" --files-from="$INPUTS" / "$BACKUP_DIR" --ignore-missing-args >> "$HOME/.simple_backup/simple_backup.log" 2>> "$HOME/.simple_backup/errors.log"
else else
rsync -acrv -H -X -R --link-dest="$LAST_BACKUP" --exclude-from="$EXCLUDE" --files-from="$INPUTS" / "$BACKUP_DIR" >> "$HOME/.simple_backup/simple_backup.log" 2>> "$HOME/.simple_backup/errors.log" rsync -acrv -H -X -R --link-dest="$LAST_BACKUP" --exclude-from="$EXCLUDE" --files-from="$INPUTS" / "$BACKUP_DIR" --ignore-missing-args >> "$HOME/.simple_backup/simple_backup.log" 2>> "$HOME/.simple_backup/errors.log"
fi fi
#Update the logs #Update the logs