Scheduled Backup and Recovery

LinuxBeginner
Practice Now

Introduction

A useful backup is more than an archive command. You must know what it contains, verify that it can be read, restore the file you need, and make unattended runs observable.

In this lab, you will back up a small application workspace from a manifest, restore one selected file, turn the workflow into a timestamped script, and install a Cron schedule. Every automated path is absolute so the job does not depend on an interactive shell's current directory.

Define the Backup Scope with a Manifest

In this step, you will create a manifest: a plain-text list of paths that makes the backup scope visible and reviewable.

Enter the workspace:

cd /home/labex/project/backup-lab

Create a manifest containing paths relative to the data directory:

cat > backup-manifest.txt <<'EOF'
config/app.conf
documents/runbook.txt
EOF

Number the entries so they are easy to review:

nl -ba backup-manifest.txt

Confirm that every listed source exists with a while loop. Read its structure before running it:

  • IFS= prevents the shell from trimming whitespace at the start or end of a line;
  • read -r item reads one complete line into item without treating backslashes specially;
  • do ... done encloses the command repeated for each line;
  • < backup-manifest.txt supplies the manifest as the loop's input;
  • test -f checks that the corresponding path is a regular file, and && prints ready only when that check succeeds.
while IFS= read -r item; do
  test -f "data/$item" && echo "ready: $item"
done < backup-manifest.txt

The unlisted documents/scratch.txt file is intentionally outside this managed backup.

Create an Archive from the Manifest

In this step, you will use tar -T to read filenames from the manifest. The -C data option makes the archive use short relative paths.

tar -czf backups/manual-backup.tar.gz -C data -T backup-manifest.txt

The options mean:

  • -c: create an archive;
  • -z: compress it with gzip;
  • -f: use the following archive filename;
  • -C data: operate relative to data;
  • -T backup-manifest.txt: read the backup members from the manifest.

Inspect the resulting file:

ls -lh backups/manual-backup.tar.gz

Compare its timestamp and size with the source files:

stat -c '%n size=%s modified=%y' backups/manual-backup.tar.gz data/config/app.conf data/documents/runbook.txt

Verify the Archive without Extracting It

In this step, you will test the archive before relying on it. First test the gzip stream:

gzip -t backups/manual-backup.tar.gz

No output means the compressed stream passed its integrity check. Now list the tar members without extracting them:

tar -tzf backups/manual-backup.tar.gz | tee archive-contents.txt

Compare the saved listing with the manifest:

diff -u backup-manifest.txt archive-contents.txt

The command should show no differences. Confirm that the unmanaged scratch file is absent:

if tar -tzf backups/manual-backup.tar.gz | grep -qx 'documents/scratch.txt'; then
  echo "Unexpected scratch file found"
else
  echo "Archive scope is correct"
fi

Restore One Selected File

In this step, you will restore only one selected file so unrelated data is not overwritten. Simulate accidental deletion of the configuration:

rm data/config/app.conf
test -e data/config/app.conf || echo "app.conf is missing"

Extract only config/app.conf into the separate restore directory:

rm -rf restore/*
tar -xzf backups/manual-backup.tar.gz -C restore config/app.conf

Inspect the recovered file, then copy it back to its working location:

cat restore/config/app.conf
cp restore/config/app.conf data/config/app.conf
cmp -s restore/config/app.conf data/config/app.conf && echo "Configuration restored"

Only the requested archive member was extracted.

Build a Timestamped Backup Script

In this step, you will build a timestamped backup script. Cron starts jobs with a limited environment, so use absolute paths inside unattended scripts.

Create backup.sh:

cat > backup.sh <<'EOF'
#!/bin/bash

source_dir=/home/labex/project/backup-lab/data
manifest=/home/labex/project/backup-lab/backup-manifest.txt
backup_dir=/home/labex/project/backup-lab/backups
timestamp=$(date +%Y%m%d-%H%M%S)
archive="$backup_dir/backup-$timestamp.tar.gz"

mkdir -p "$backup_dir"

if [ ! -d "$source_dir" ] || [ ! -f "$manifest" ]; then
  echo "Backup source or manifest is missing" >&2
  exit 1
fi

/bin/tar -czf "$archive" -C "$source_dir" -T "$manifest" || exit 1
/bin/tar -tzf "$archive" > "$archive.contents" || exit 1

echo "Created $archive"
exit 0
EOF

Make the script executable and test it now instead of waiting for Cron:

chmod u+x backup.sh
./backup.sh | tee last-backup.txt
ls -1 backups

The timestamp gives each run a unique filename. The companion .contents file records exactly what the archive contains.

Install and Inspect a Cron Schedule

In this step, you will install and inspect a personal Cron schedule. A crontab line begins with five scheduling fields, followed by the command:

Position Field Usual range
1 minute 059
2 hour 023
3 day of month 131
4 month 112
5 day of week 07, where Sunday is 0 or 7

An asterisk * means every allowed value. A step such as */5 means every five units in that field.

minute hour day-of-month month day-of-week command

For example, */5 * * * * means every five minutes. 0 2 * * * means 02:00 every day.

crontab -e opens your personal crontab in an editor. A reliable workflow is to prepare and install a known-good entry first, then make a small interactive edit. Create one entry that uses absolute paths and captures both standard output and standard error:

cat > backup.crontab <<'EOF'
*/5 * * * * /home/labex/project/backup-lab/backup.sh >> /home/labex/project/backup-lab/logs/backup.log 2>&1
EOF

Review and install it:

cat backup.crontab
crontab backup.crontab

Now open the installed crontab in Nano:

EDITOR=nano crontab -e

Add this comment on the line above the schedule:

## LabEx managed backup schedule

Press Ctrl+O, then Enter to save. Press Ctrl+X to leave Nano and return to the shell. Use crontab -l to confirm exactly what Cron will read and save that output:

crontab -l | tee installed-crontab.txt

The output should contain the comment followed by the every-five-minutes entry. Inspecting the installed result catches editor mistakes before you depend on the schedule.

Test Logging and Understand Percent Escaping

In this step, you will test backup logging and learn Cron's special handling of percent signs. First run the scheduled command manually:

/home/labex/project/backup-lab/backup.sh >> /home/labex/project/backup-lab/logs/backup.log 2>&1
tail -n 5 logs/backup.log
find backups -maxdepth 1 -type f -name 'backup-*.tar.gz' -printf '%f\n' | sort

The timestamp is created inside backup.sh, where ordinary % characters are safe. Cron treats an unescaped % in a crontab command specially, however. If you place date directly in a crontab line, escape each percent sign with a backslash.

Save a correctly escaped example for reference:

cat > cron-date-example.txt <<'EOF'
0 2 * * * /bin/echo "backup-$(/bin/date +\%Y\%m\%d-\%H\%M\%S)" >> /home/labex/project/backup-lab/logs/date-example.log 2>&1
EOF
cat cron-date-example.txt

Your installed job remains the simpler script-based entry. It uses absolute paths, gives every archive a timestamp, and leaves a log that can be inspected after unattended runs.

Summary

You defined a backup scope in a manifest, created an archive with tar -T, verified it without extraction, and recovered one selected file. You then wrote a timestamped backup script with absolute paths, installed and inspected a Cron schedule, redirected unattended output to a log, and learned why percent signs must be escaped when date appears directly in a crontab command.