# Exercise: The Health Check

Finish a health check script for a book club's home server: read the disk, memory, load and failed services, warn about each problem, and exit with a code that says whether all is well, while a check script runs it on a pretend computer, job by job.

Journeyman · Unix · Linux · Updated November 10, 2026

The book club's website runs on a small home server in Sam's closet, and Sam doesn't want to sign in every morning to read four gauges. The club wants one command that answers "does the server need a look?": a line each for the disk, the memory, the load and the services, a plain warning for each problem, and an exit code that says whether all is well, so another script can act on it. You'll finish `health.sh`, and a check script runs it on a pretend computer with a full disk, too little memory or a failed service, job by job.

## Before you start

You need a terminal: Ubuntu on Linux or in WSL on Windows, or the Terminal app on a Mac. The check runs with **bats**, from *Testing Scripts with bats*. 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. `health.sh` reads `free` and `systemctl`, which Linux and WSL have and a Mac doesn't; on a Mac, the check still works, because it brings its own pretend versions.

## Get the exercise code

Open this lesson's GitHub repository, [github.com/ask-codey/exercise-bash-the-health-check](https://github.com/ask-codey/exercise-bash-the-health-check), 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:

- `health.sh`: the health check to finish, with five jobs, each a comment that says what to read, what to print and when to warn.
- `check.bats`: the check. You don't need to change it.

## What to do

`cd` into the exercise folder, run `chmod +x health.sh`, and open it with `nano health.sh`. Strict mode, the `warnings` list and the first line are there already. Each job is a comment, with room under it for your lines:

```text
# 1. Disk. Read how full the main disk is, as a number without the %:
#    the fifth column of the second line of  df /  (tr -d % takes the % off).
#    Print:  Disk:    42% of / used
#    When it's 90 or more, add the warning:
#      the disk is 95% full. Find what's filling it with du.
```

1. **Disk:** the `Use%` of `/` from `df /`, a `Disk:` line, and a warning at 90% or more.
2. **Memory:** the total and available MB from `free -m`, a `Memory:` line, and a warning when less than 10% is available.
3. **Load:** the 1-minute load from `uptime` and the CPUs from `nproc`, a `Load:` line, and a warning when the load's whole number is at least the number of CPUs.
4. **Failed services:** their names from `systemctl --failed --no-legend --plain`, a `Failed services:` line with how many, and a warning for each.
5. **The verdict:** every warning, each on a line that starts `WARNING: `, then `All OK.` and exit code 0, or `Warnings:` and the number, and exit code 1.

Each job's comment gives its line and its warning word for word. Save, and run `./health.sh` as you go.

## 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 checks into a ✓. A failing check names its job, says what it expected and shows what your script printed, for example *Job 1: with the disk 42% full, health.sh should print the line  Disk:    42% of / used*. The check makes small stand-ins for `df`, `free`, `uptime`, `nproc` and `systemctl` in a throwaway folder of its own, so it can pretend the disk is full without touching yours. Its last check runs `health.sh` on your own computer.

## Hints

- **Try each reading at the prompt first.** `df / | awk 'NR == 2 {print $5}'` should print your disk's percentage; then add `| tr -d %` and save it with `$( )` (*Values from Commands: $( ) and $(( ))*).
- **`(( ))` compares whole numbers**, so `free -m` (MB) works and `free -h` (`3.8Gi`) doesn't. For the 10%, multiply first: `available * 100 / total`.
- **The load has a dot in it**, and `(( ))` can't count with that. `${load%.*}` cuts off the dot and what follows, the way `${f%.tmp}` cut off an ending in *For Every File: for Loops*.
- **Each failed service's name** is the first word of its line. Loop over them with `for`, counting as you go (*Stopping Early: break, continue and Counters*).
- **Job 5 is two parts:** a `for` loop over `"${warnings[@]}"`, then `${#warnings[@]}` to choose `All OK.` or `Warnings:` (*Arrays*).

## When you're done

Every check passes:

```text
check.bats
 ✓ the script is here and bash can read it
 ✓ 1) the disk line
 ✓ 1) a disk 90% full or more gets a warning
 ✓ 2) the memory line
 ✓ 2) less than 10% of memory available gets a warning
 ✓ 3) the load line
 ✓ 3) a load of one per CPU or more gets a warning
 ✓ 4) failed services are counted
 ✓ 4) each failed service gets a warning
 ✓ 5) a healthy computer: All OK. and exit code 0
 ✓ 5) two problems: two warnings, Warnings: 2 and exit code 1
 ✓ it runs on this computer too

12 tests, 0 failures
```

And on Sam's laptop, `./health.sh` then `echo $?` prints this; yours shows your own computer's numbers:

```text
Health check, 2026-11-09 14:42
Disk:    4% of / used
Memory:  62043 MB available of 64194 MB
Load:    0.42 on 24 CPUs
Failed services: 0
All OK.
0
```

Want to see a warning on your own computer? Change job 1's 90 to 1 for a moment, run it, and change it back. Then think about the exit code: what could a script that runs `health.sh` every morning do with a 1 that it couldn't do with the words alone?

## 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-health-check`), 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-health-check.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-health-check.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-health-check`, 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

You've built the check an administrator runs first on any server, written so both people and other scripts can read its answer: plain lines for you, and an exit code for the script that runs it on a schedule.

## Key terms

- [Load Average](https://www.ask-codey.com/glossary/load-average)
- [Available Memory](https://www.ask-codey.com/glossary/available-memory)
- [df and du](https://www.ask-codey.com/glossary/df-and-du)
- [systemctl](https://www.ask-codey.com/glossary/systemctl)
- [Exit Code](https://www.ask-codey.com/glossary/exit-code)
- [Health Check](https://www.ask-codey.com/glossary/health-check-operating-system)

## Related

- [Is It Healthy? Memory, Load and Uptime](https://www.ask-codey.com/lessons/bash-system-health)
- [Services: systemctl](https://www.ask-codey.com/lessons/bash-services)
- [Reading System Logs](https://www.ask-codey.com/lessons/bash-system-logs)
- [Users and Groups](https://www.ask-codey.com/lessons/bash-users-and-groups)

Source: https://www.ask-codey.com/lessons/exercise-bash-the-health-check
