# Exercise: The Smart Backup

Finish a backup script that copies a file only when it's needed, with a usage line, --help, --list and a --pick menu, checks for missing, empty and folder names, and a clear message when a copy fails, while a check script runs it job by job.

Apprentice · Unix · Linux · Updated November 10, 2026

Your school work deserves a backup, and the one you'll finish here is smart about it. It copies a file only when the file changed since its last copy, never lets an empty file replace a good one, refuses folders and typos with a clear message, and says plainly when a copy fails. It also behaves like a real application: run it wrong and it explains itself, `--help` shows how to use it, `--list` shows what's backed up, and `--pick` offers a numbered menu. A check script runs your script for real, job by job, and tells you which ones work.

## Before you start

You need a terminal: the Terminal app on a Mac, or Ubuntu on Linux or in WSL on Windows. The check runs with **bats**, a small program that runs checks written for bash. If `bats --version` doesn't print a version number yet, install it:

```bash
sudo apt install bats       # Ubuntu, and Ubuntu in WSL
brew install bats-core      # a Mac, with Homebrew
```

`sudo` asks for your password, the one you use to sign in; nothing shows on the screen while you type it.

## Get the exercise code

Open this lesson's GitHub repository, [github.com/ask-codey/exercise-bash-the-smart-backup](https://github.com/ask-codey/exercise-bash-the-smart-backup), also linked from the **Exercise** box beside the lesson. Click **Code**, then **Download ZIP**, and unzip it into your `terminal-practice` folder. Or clone it with Git.

The folder holds:

- `smart-backup.sh`: the script to finish, with its usage line and nine jobs, each a comment saying what to do and exactly what to print.
- `essay.txt`, `notes.txt`, `reading-list.txt`, `empty-draft.txt` and a `photos` folder: practice files to try it on.
- `check.bats`: the check. You don't need to change it.

## What to do

Open a terminal and `cd` into the exercise folder. Let the script run with `chmod +x smart-backup.sh` (*Your First Script*), then open it with `nano smart-backup.sh`. Each job is a comment, with room under it for your lines:

```text
usage="Usage: ./smart-backup.sh FILE, or --list, --pick or --help"

# 1. Run with nothing after its name: print the usage line, and stop with
#    exit code 1.
```

1. **Run with nothing**: print the usage line and stop with exit code 1 (*If This, Then That: if and [[ ]]*).
2. **`--help` or `-h`**: print the usage line and stop with exit code 0.
3. **`--list`**: list what's in `backup/`, or say `No backups yet.` when there's no backup folder.
4. **`--pick`**: a numbered menu of the `.txt` files that asks `Back up which file? ` and backs up the one picked (*Menus and Choices: case and select*). Jobs 2 to 4 fit in one `case`.
5. **A missing file**: say so and stop with exit code 1 (*Checking Before You Act: File Tests*).
6. **A folder**: say so and stop with exit code 1.
7. **An empty file**: keep the last good copy, and stop with exit code 0.
8. **Copy only when needed**: go on when the file is newer than its copy in `backup/`, or has no copy yet; otherwise say it hasn't changed.
9. **Say whether the copy worked**: `Copied FILE.`, or the failure message and exit code 1.

Each job's comment gives its message word for word. Save, and try your script on the practice files as you go: `./smart-backup.sh essay.txt` twice, then `./smart-backup.sh --list`.

## Check your work

From the exercise folder:

```bash
bats check.bats
```

At first most checks fail. That's expected: each job you finish turns its check into a ✓. A failing check says what it expected, what your script printed, and what to look at, for example *With no backup folder, --list should say so. Test for the folder with -d.* The check runs your script in a throwaway folder of its own, with made-up files, so your practice files and your `backup/` folder are never touched.

## Hints

- **Work from the top.** Job 1 comes first, so a script run with nothing stops before it tries anything else.
- **Spaces inside the brackets**: `[[ $# -lt 1 ]]`, never `[[$# -lt 1]]`. Numbers compare with `-lt`, text with `==`.
- **One `case` for jobs 2 to 4.** A choice can match two patterns, `-h|--help)`; end each choice with `;;` and the whole thing with `esac`. A name that matches no choice goes straight on to job 5.
- **The menu's question is `PS3`**, set before `select`. Name the menu's variable `file`, and end the menu with `break` so the script carries on.
- **Turn a test around with `!`**: `[[ ! -s "$file" ]]` passes when the file is empty. And `-nt` counts a missing copy as older, so one test covers "changed" and "never backed up".
- **Put `cp` itself after `if`** for job 9, and quote every `"$file"`: the check tries a name with a space in it.

## When you're done

Every check passes:

```text
check.bats
 ✓ the script is here and bash can read it
 ✓ 1) run with nothing, it prints the usage line and stops
 ✓ 2) --help and -h print the usage line
 ✓ 3) --list says when there are no backups yet
 ✓ 3) --list shows what's in backup/
 ✓ 4) --pick shows a menu and backs up the file picked
 ✓ 5) a missing file: it says so and stops
 ✓ 6) a folder: it says so and stops
 ✓ 7) an empty file: it keeps the last good copy
 ✓ 8) a file with no copy yet is copied, and backup/ is made
 ✓ 8) a name with spaces works
 ✓ 8) an unchanged file isn't copied again
 ✓ 8) a changed file is copied again
 ✓ 9) a copy that fails says so

14 tests, 0 failures
```

And by hand, in the exercise folder, the script answers like this (with `3` typed at the menu):

```text
$ ./smart-backup.sh
Usage: ./smart-backup.sh FILE, or --list, --pick or --help
$ ./smart-backup.sh essay.txt
Copied essay.txt.
$ ./smart-backup.sh essay.txt
essay.txt hasn't changed since the last backup.
$ ./smart-backup.sh --pick
1) empty-draft.txt   3) notes.txt
2) essay.txt         4) reading-list.txt
Back up which file? 3
Copied notes.txt.
```

Now look back at your job 8. A friend asks for a backup that copies every file every time, "to be safe". What would that cost on a folder of 2,000 photos, and what could it do to a good copy?

## Submit your exercise

The exercise is how you finish this lesson. When your work is done, put it on GitHub in a repo of your own, then submit that repo's address here.

1. On GitHub, click **+**, then **New repository**. Name it (for example `exercise-bash-the-smart-backup`), choose **Public**, and click **Create repository**. Leave out the README: your folder already has one.
2. In a terminal in your exercise folder (Ubuntu in WSL on Windows), send your work to your new repo. If you downloaded the ZIP:

   ```bash
   git init -b main
   git add .
   git commit -m "My solution"
   git remote add origin https://github.com/your-name/exercise-bash-the-smart-backup.git
   git push -u origin main
   ```

   If you cloned the starter instead, point your copy at your own repo, then commit and push:

   ```bash
   git remote set-url origin https://github.com/your-name/exercise-bash-the-smart-backup.git
   git add .
   git commit -m "My solution"
   git push -u origin main
   ```

3. Paste your repo's address, such as `https://github.com/your-name/exercise-bash-the-smart-backup`, into **Submit your exercise** on this page. The site checks that the repo is public and holds your commits, and then the lesson is complete.

Changed something after you submitted? Push it, and submit again: your latest submission is the one that counts.

## So what

Your script now makes decisions the way real backup tools do: it checks before it acts, copies only what changed, and tells the person running it what happened. That's the difference between a list of commands and an application.

## Key terms

- [if Statement](https://www.ask-codey.com/glossary/if-statement-unix)
- [Test Command](https://www.ask-codey.com/glossary/test-command)
- [File Test](https://www.ask-codey.com/glossary/file-test)
- [case Statement](https://www.ask-codey.com/glossary/case-statement)
- [select](https://www.ask-codey.com/glossary/select-unix)
- [Exit Code](https://www.ask-codey.com/glossary/exit-code)

## Related

- [If This, Then That: if and \[\[ \]\]](https://www.ask-codey.com/lessons/bash-if-statements)
- [Checking Before You Act: File Tests](https://www.ask-codey.com/lessons/bash-file-tests)
- [Menus and Choices: case and select](https://www.ask-codey.com/lessons/bash-case-and-select)

Source: https://www.ask-codey.com/lessons/exercise-bash-the-smart-backup
