# Exercise: Three Things at Once

Write three tools for a day's work on Bluebird Bakery's website: three-panes.sh sets up the server, the tests rerunning in watch and a free terminal in one tmux session, wait-for-site.sh waits for the site and gives up at a time limit, and resize-all.sh resizes photos four at a time, while a check script tells you what's done.

Freelancer · Unix · Linux · Updated November 10, 2026

A day's work on Bluebird Bakery's website means three things at once: the site's server running, its tests rerunning every few seconds, and a terminal to type in. There are twelve vacation photos to shrink for the site, too. You'll write one tool for each lesson of this chapter: `three-panes.sh`, which sets up all three in one tmux session with one command; `wait-for-site.sh`, which waits until the site answers and gives up at a time limit; and `resize-all.sh`, which resizes the photos four at a time. A check script tells you what's 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**, and the exercise uses **tmux**, **watch**, **curl** and **python3**, which runs the practice web server. Check each one with `--version` (`tmux -V` for tmux), and install what's missing:

```bash
sudo apt install bats tmux curl python3       # Ubuntu, and Ubuntu in WSL
brew install bats-core tmux watch coreutils   # 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. Ubuntu already has `watch`. A Mac already has `curl` and `python3`, and `coreutils` adds `timeout`.

## Get the exercise code

Open this lesson's GitHub repository, [github.com/ask-codey/exercise-bash-three-things-at-once](https://github.com/ask-codey/exercise-bash-three-things-at-once), 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 inside Ubuntu, in your Linux home folder, not in a Windows folder under `/mnt/c`, so `chmod` works on the scripts.

The folder holds:

- `answers.txt`: five questions, each with a numbered line for your answer.
- `three-panes.sh`, `wait-for-site.sh` and `resize-all.sh`: the three tools. Each starts with a comment that says exactly what it must do and print. These, and `answers.txt`, are the files you write.
- `site/`, `start-server.sh` and `test.sh`: the bakery's website, the script that serves it at `http://localhost:8000` after a few seconds, and the tests from *Waiting for Things: watch, until and timeout*.
- `photos/` and `resize.sh`: twelve pretend photos, a packing list that ended up among them, and the one-second stand-in resizer from *Running Work in Parallel: &, wait and xargs -P*.
- `check.bats`: the check. You don't need to change it.

## What to do

Open a terminal in the exercise folder, and make the scripts runnable:

```bash
chmod +x *.sh
```

1. **Answer the questions** in `answers.txt`, trying each one in tmux or the terminal first. Write each answer after its `)`, like the example: `0) tmux new -s bakery`.
2. **Write `three-panes.sh`.** One session named `bakery`, with three panes: `./start-server.sh`, `watch -n 5 ./test.sh`, and a free terminal. Run it, watch the tests turn from `000` to `200` as the server starts, then detach with Ctrl+B `d` and run it again: you're back in the same session, not a new one. `tmux kill-session -t bakery` ends it.
3. **Write `wait-for-site.sh URL [SECONDS]`.** With the server stopped, `./wait-for-site.sh http://localhost:8000/ 5` gives up after five seconds. Start the server in another pane, run it again, and it says the site is up as soon as it answers.
4. **Write `resize-all.sh`.** Four at a time, every photo and nothing else, and it finishes only when the last photo is done. `time ./resize-all.sh` shows the difference: about three seconds instead of twelve.

## Check your work

From the exercise folder:

```bash
bats check.bats
```

At first almost every check fails. That's expected: each question you answer and each tool you finish turns its check into a ✓. The check tries your scripts on copies in a throwaway folder, with a practice website on a free port and a tmux of its own, so it never touches your own sessions or your server. It stops only what it started, and takes about 20 seconds. A failing check says what to look at, for example *resize.sh ran one photo at a time, so it took 12 seconds. Run up to 4 at once with xargs -n 1 -P 4.*

## Hints

- **A session from a script:** `tmux new -d -s bakery COMMAND` makes it without attaching, with the command in its first pane. `tmux split-window` takes a command too, and `tmux has-session -t bakery` succeeds only when the session exists (*tmux: Panes, Windows and Sessions*).
- **A default:** `${2:-30}` is the second argument, or 30 when there isn't one.
- **Waiting with a limit:** `until curl -s -o /dev/null "$url"; do sleep 1; done` waits for an answer, and `timeout` stops it at the limit with exit code 124. `timeout` runs one command, so the loop goes inside `bash -c '...'` (*Waiting for Things: watch, until and timeout*).
- **Only the photos, spaces and all:** `find -name '*.jpg' -print0` and `xargs -0` keep each name whole, `-n 1` gives each `resize.sh` one name, and `-P 4` runs four at once (*Running Work in Parallel: &, wait and xargs -P*).
- **Counting what's done:** `small=(small/*)` puts every file in `small/` into an array (*Arrays*), and `${#small[@]}` is how many there are.

## When you're done

Every check passes:

```text
check.bats
 ✓ the scripts, the site and the photos are here
 ✓ 1) the key that splits a pane side by side
 ✓ 2) the key that detaches
 ✓ 3) the command that brings back the session bakery
 ✓ 4) the command that reruns the tests every 5 seconds
 ✓ 5) the exit code timeout gives when it stops a command
 ✓ 6) wait-for-site.sh with no URL shows how to use it
 ✓ 7) wait-for-site.sh waits for a server that is starting up
 ✓ 8) wait-for-site.sh gives up after SECONDS
 ✓ 9) wait-for-site.sh waits 30 seconds when SECONDS isn't given
 ✓ 10) resize-all.sh resizes every photo and nothing else
 ✓ 11) resize-all.sh runs four at a time
 ✓ 12) resize-all.sh waits for every photo, then counts them
 ✓ 13) three-panes.sh makes the session bakery with three panes
 ✓ 14) the server runs in one of the panes
 ✓ 15) the tests rerun every 5 seconds in another pane
 ✓ 16) three-panes.sh run a second time makes nothing new

17 tests, 0 failures
```

Now put two of your tools together: which line, added to `three-panes.sh` after the session is made, would wait until the site answers before attaching, and give up after 30 seconds?

## Looking back

This is the last exercise of Bash in Depth. Think back to the first chapter: you typed `pwd` in a practice folder called `trip`, and the terminal answered with a path you had to learn to read. Since then you've moved, copied and deleted files without a mouse, searched a month of logs in a second, set up your shell the way you like it, and written scripts that take arguments, make decisions, loop, fail well and report back: a recipe box app, a weather report from a real web service, a backup that runs while you sleep, a deploy over SSH. In this chapter you ran a server, its tests and your own typing side by side, and made a computer do four jobs at once.

That doesn't mean you know every command, and nobody does. It means the terminal is a place you can work, a manual page or `--help` is something you can read, and a script file is an application you can write whenever a job calls for one. The mouse is still there, and it's still the better tool for plenty of jobs; now you have a choice. A good next step is a job you do by hand every week: write the script for it.

## 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-three-things-at-once`), 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-three-things-at-once.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-three-things-at-once.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-three-things-at-once`, 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

A server, its tests and your typing side by side, a wait that knows when to give up, and work spread over every core: that's a developer's terminal, and you built it from scripts you wrote yourself.

## Key terms

- [tmux](https://www.ask-codey.com/glossary/tmux)
- [watch](https://www.ask-codey.com/glossary/watch-unix)
- [timeout](https://www.ask-codey.com/glossary/timeout)
- [xargs](https://www.ask-codey.com/glossary/xargs)
- [Parallel Processing](https://www.ask-codey.com/glossary/parallel-processing)

## Related

- [tmux: Panes, Windows and Sessions](https://www.ask-codey.com/lessons/bash-tmux)
- [Waiting for Things: watch, until and timeout](https://www.ask-codey.com/lessons/bash-watch-and-wait)
- [Running Work in Parallel: &, wait and xargs -P](https://www.ask-codey.com/lessons/bash-parallel-jobs)

Source: https://www.ask-codey.com/lessons/exercise-bash-three-things-at-once
