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

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:

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, 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:

# 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:

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

Check your work

From the exercise folder:

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:

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):

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:

    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:

    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

Related