How to Back Up Directories using Shell Script

Related to the task of backing up entire file systems is the user-centric task of taking a snapshot of a specific directory or directory tree. This simple script allows users to easily create a compressed tar archive of a specified directory.

The Code
#!/bin/sh

# archivedir - Creates a compressed archive of the specified directory.

maxarchivedir=10 # size, in blocks, of 'big' directory
compress=gzip # change to your favorite compress app
progname=$(basename $0)

if [ $# -eq 0 ] ; then
echo "Usage: $progname directory" >&2 ;exit 1
fi

if [ ! -d $1 ] ; then
echo "${progname}: can't find directory $1 to archive." >&2; exit 1
fi

if [ "$(basename $1)" != "$1" -o "$1" = "." ] ; then
echo "${progname}: You must specify a subdirectory" >&2
exit 1
fi

if [ ! -w . ] ; then
echo "${progname}: cannot write archive file to current directory." >&2
exit 1
fi

dirsize="$(du -s $1 | awk '{print $1}')"

if [ $dirsize -gt $maxarchivedir ] ; then
echo -n "Warning: directory $1 is $dirsize blocks. Proceed? [n] "
read answer
answer="$(echo $answer | tr '[:upper:]' '[:lower:]' | cut -c1)"
if [ "$answer" != "y" ] ; then
echo "${progname}: archive of directory $1 canceled." >&2
exit 0
fi
fi
archivename="$(echo $1 | sed 's/$/.tgz/')"

if tar cf - $1 | $compress > $archivename ; then
echo "Directory $1 archived as $archivename"
else
echo "Warning: tar encountered errors archiving $1"
fi

exit 0

How It Works
This script is almost all error-checking code, to ensure that it never causes a loss of data or creates an incorrect snapshot. In addition to the typical tests to validate the presence and appropriateness of the starting argument, this script also forces the user to be in the parent directory of the subdirectory to be compressed and archived, which ensures that the archive file is saved in the proper place upon completion. The conditional if [ ! -w . ] ; then verifies that the user has write permission on the current directory. And this script even warns users before archiving if the resultant backup file would be unusually large.

Finally, the actual command that archives the specified directory is

tar cf - $1 | $compress > $archivename

The return code of this command is tested to ensure that the script never deletes the directory if an error of any sort occurs.

Running the Script
This script should be invoked with the name of the desired directory to archive as its only argument. To ensure that the script doesn't try to archive itself, it requires that a subdirectory of the current directory be specified as the argument, rather than ".".

The Results
$ archivedir scripts
Warning: directory scripts is 2224 blocks. Proceed? [n] n
archivedir: archive of directory scripts canceled.

This seemed as though it might be a big archive, so I hesitated to create it, but thinking about it, there's no reason not to proceed after all:

$ archivedir scripts
Warning: directory scripts is 2224 blocks. Proceed? [n] y
Directory scripts archived as scripts.tgz


The results:

$ ls -l scripts.tgz
-rw-r--r-- 1 taylor staff 325648 Jul 14 08:01 scripts.tgz