Share on facebook
Share on twitter
Share on linkedin

How to write a backup script with Bash

Rob Marti
Rob Marti

Linux System Administrators often have a lot of manual tasks that need to be attended to daily. One way to make some of that work easier is to automate things. Bash scripting is a flexible and easy way to make use of your existing command-line knowledge to automate tasks you run often — and do so in a way that other admins can be reasonably expected to help maintain. As an example, let’s walk through a backup script together.

Bash scripting has been around essentially as long as shells have existed. Understanding the reason why is pretty simple: automation makes things easier on the administrator. And really, who wants to make their job harder?

What’s in store for Linux in 2021? Check out Linux This Month for that and all the latest in all things Linux.

First, I want to be clear and say that my method is not the perfect, no-room-for-improvement, must-be-done-this-way method. My scripts are legible and easily maintainable, but they’re not the only way to do things.

Let’s take a look at the following script:

https://raw.githubusercontent.com/linuxacademy/the-system-admin-guide-to-bash-scripting/master/backup-blog.sh

The first section starts off like this:

-----
#!/bin/bash

#####
# This is a script given to users on a machine when they want to back 
# up their work to a specific backup directory (/home/$USER/work_backup)
# 
# The script requires two parameters - the first is where the log file 
# will be and the second is what directory will be backed up.
#####
-----

The shebang is essentially required to be the first line. It lets the shell know what binary we’re going to be executing the following code with. (For example, if you were going to write a python script, it would be appropriate to put the path to the python binary there).

The next part is some text that is entirely commented out, so the shell won’t parse that as code (the # at the beginning of the line). I use that area to explain what the script does, and if there are any parameters that need to be passed to the script.

-----
if [ -z "$1" ] || [ -z "$2" ]; then
	echo "You have failed to pass a parameter."
	echo "Reminder that all required files will be copied to /home/\$USER/work/work_backup."
	echo "USAGE: ./backup.sh LOGFILE DIRECTORY-TO-BACKUP"
	exit 255;
fi


MYLOG=$1
BACKUP_FROM=$2
-----

Here we verify that the required parameters were passed — if not, exit the script with some usage information. After that we can assign the parameters to variables with names that make more sense. After all, if your script is a few hundred lines long, would you rather remember that the log file variable is called MYLOG or 1?

This isn’t the only way to handle parameters — but it is the simplest way to do so. For this short of a script I think it’s entirely appropriate. What do you think?

-----
function ctrlc {
	rm -rf /home/$USER/work/work_backup
	rm -f $MYLOG
	echo "Received Ctrl+C"
	exit 255
}

trap ctrlc SIGINT
-----

In this section we ask the question “What do we do if someone tries to cancel the script while it’s running?” When a user hits Ctrl+C, the script will trap that  signal and run our function that undoes all the work done so far and makes sure the user knows why the script stopped unexpectedly.

-----
echo "Timestamp before work is done $(date +"%D %T")" >> $MYLOG

echo "Creating backup directory" >> $MYLOG
if ! (mkdir /home/$USER/work/work_backup 2> /dev/null)
then
	echo "Directory already existed." >> $MYLOG
fi
-----

Here we’re making sure that we log when we started the work, because logging is vital to troubleshooting. If your system logs have disk errors starting at 10:30 a.m.  and your script started to run at 10:31 a.m. and generated errors, it’s probably not  the script’s fault.

Following that, we create the directory that we’re going to copy files into. We do so using an if statement that says “If we failed to create the directory it’s

because it already exists.” There could be an issue if we’re running the script in a place where we don’t have permission to create directories/files, and that’s certainly a place where this script could be improved, but this setup will work for normal usage.

-----
echo "Copying Files" >> $MYLOG
cp -v $BACKUP_FROM/* /home/$USER/work/work_backup/ >> $MYLOG
echo "Finished Copying Files" >> $MYLOG
echo "Timestamp after work is done $(date +"%D %T")" >> $MYLOG
-----

Finally, we get to where most of the work happens. First, we log that we’re about to actually do the work, then we run our copy command. As far as potential improvements to this script, you could replace this with a loop that will rename all the files,  either adding the “-backup” tag, the date the file was copied, or what have you. For most purposes, however, this method will do just fine.

Once complete, we log that we’re done, and then log the timestamp — again, to assist with troubleshooting.

That’s it! Thanks for reading this post and following with me on my thought process behind writing a script. Using Bash to script out and automate common tasks can (and will) save time in the long run. Feel free to use this script and modify it as needed for whatever you want. 

Check out the SysAdmin’s Guide to Bash Scripting

Want to learn more tips and tricks with Bash scripting? Take a look at my newly released course The System Administrator’s Guide to Bash Scripting. I’d love to be part of your learning adventure.

Questions? Feel free to contact me!


Level up your Linux know-how

Learn Linux skills by getting hands on with A Cloud Guru. See why 85% of our learners say they retain more by doing.

Get Started
Who’s going to be learning?
Sign In
Welcome Back!

Psst…this one if you’ve been moved to ACG!