# Exercise: The Greeting Card Maker

Finish card.sh, a small application that takes a name as its argument, asks for a greeting and a signature, and saves a dated, numbered card, then fix its quoting bug and let a check script run it for real.

Apprentice · Unix · Linux · Updated November 10, 2026

Every birthday and every thank-you in your family goes through you, and you're tired of writing the same card by hand. In this exercise you finish `card.sh`, a greeting card maker that runs like any other application: you give it a name, it asks two questions, and it saves a card named after the person and the date, numbered so you can see how many you've sent. Half the script is written for you, and that half has the number-one bash bug in it. A check script runs your card maker for real, with names and greetings chosen to catch that bug, and tells you which jobs are done.

## 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-greeting-card-maker](https://github.com/ask-codey/exercise-bash-the-greeting-card-maker), 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. On Windows, put it in your Ubuntu home folder, not under `/mnt/c`, so `chmod` works on it.

The folder holds:

- `card.sh`: the card maker, with an example done and six jobs, each a comment saying what to add or fix.
- `check.bats`: the check. You don't need to change it.

## What to do

Open a terminal in the exercise folder, make the script runnable with `chmod +x card.sh`, and open it with `nano card.sh`. Each job is a comment, with room under it for your lines:

```text
# 1. Keep the first argument, the person the card is for, in a variable called name.
```

1. **The name**: keep the first argument in `name` (*Arguments: $1, $# and "$@"*).
2. **The greeting**: ask `Greeting [Happy birthday]: ` with `read -r -p`, and make `Happy birthday` the answer when someone presses Enter (*Asking Questions: read*).
3. **The signature**: ask `Signed by: ` and keep the answer in `from`.
4. **Today's date**: keep it, as year-month-day, in `today`, with `$( )` and `date` (*Values from Commands: $( ) and $(( ))*).
5. **The card's number**: one more than the number of cards already in the `cards` folder, worked out with `$(( ))`.
6. **The bug**: the lines that write the card are already there, but none of them has quotes. Run `./card.sh "Aunt Rosa"` once jobs 1 to 5 work, read what goes wrong, and fix every line (*Quotes: Double, Single and None*).

Save, then run your card maker after each job and read the card it made:

```bash
./card.sh Maya
cat cards/Maya-*.txt
```

## 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 names the job and gives a hint, for example *./card.sh "Aunt Rosa" should save cards/Aunt Rosa-2026-11-09.txt, but it printed: ./card.sh: line 34: $file: ambiguous redirect*. The check runs a copy of your script in a throwaway folder and types the answers for it, so your own `cards` folder isn't touched.

## Hints

- **Nothing is saved, or the card says `Dear ,`?** Job 1 isn't done yet: the lines in job 6 use `$name`.
- **An empty answer** is an empty variable, so `${greeting:-Happy birthday}`, on the line after the `read`, fills in the default.
- **The card's number:** `$(ls cards | wc -l)` counts the cards already there; put it inside `$(( ... + 1 ))`.
- **"ambiguous redirect"** means the file name after `>` or `>>` fell apart at a space. Double quotes around `"$file"` keep it whole.
- **A `*` in the greeting turned into file names?** That line's `$greeting` needs double quotes too: `echo "$greeting!"`.

## When you're done

Every check passes:

```text
check.bats
 ✓ card.sh is here, and bash can read it
 ✓ 1) the card is for the name given as the first argument
 ✓ 2) the greeting is asked for, with Happy birthday when the answer is empty
 ✓ 3) the card is signed with the second answer
 ✓ 4) the card is named and dated with today's date
 ✓ 5) every card gets the next number
 ✓ 6) a name with a space comes out exactly as typed
 ✓ 6) a greeting with a * and two spaces comes out exactly as typed
 ✓ 6) it says which card it saved

9 tests, 0 failures
```

And your card maker works like this, with your own date (here, Enter at the first question, then `Sam`):

```text
Greeting [Happy birthday]:
Signed by: Sam
Card 1 saved: cards/Maya-2026-11-09.txt
Dear Maya,

Happy birthday!

From Sam
Card 1, made on 2026-11-09
```

Now make it yours. Put it in your `~/bin` folder as `card`, as in *Run It from Anywhere: ~/bin on Your PATH*, and it runs from any folder like any other command, saving the cards in a `cards` folder wherever you run it. What would you ask next: a closing line, or the person's age, worked out with `$(( ))`?

## 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-greeting-card-maker`), 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-greeting-card-maker.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-greeting-card-maker.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-greeting-card-maker`, 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

`card.sh` is a real application in a few lines of text: it takes input from its arguments and from questions, builds values from other commands, and handles any name you give it, spaces and all.

## Key terms

- [Positional Parameter](https://www.ask-codey.com/glossary/positional-parameter-unix)
- [read](https://www.ask-codey.com/glossary/read-unix)
- [Quoting](https://www.ask-codey.com/glossary/quoting)
- [Command Substitution](https://www.ask-codey.com/glossary/command-substitution)
- [Arithmetic Expansion](https://www.ask-codey.com/glossary/arithmetic-expansion)
- [Shell Script](https://www.ask-codey.com/glossary/shell-script)

## Related

- [Arguments: $1, $# and "$@"](https://www.ask-codey.com/lessons/bash-script-arguments)
- [Asking Questions: read](https://www.ask-codey.com/lessons/bash-reading-input)
- [Quotes: Double, Single and None](https://www.ask-codey.com/lessons/bash-quoting)
- [Values from Commands: $( ) and $(( ))](https://www.ask-codey.com/lessons/bash-command-substitution)

Source: https://www.ask-codey.com/lessons/exercise-bash-the-greeting-card-maker
