# Exercise: The Website Log Report

Change the bakery's phone number on every web page with sed, keeping a backup of each, save the five most visited pages with a pipeline, and answer five questions about a week of the website's log and orders with awk, then let a check script tell you what's done.

Journeyman · Unix · Linux · Updated November 10, 2026

Bluebird Bakery's phone number has changed, and it's printed on the website's pages. The owner also wants to know how last week went online: which pages people visit, which missing pages they keep asking for, who keeps failing to log in, and how October's sales came out. The website wrote every visit into its log, 373 lines of it, and the orders are in a CSV file. Your job is to fix the pages with `sed` and build the report with `awk`, `sort` and `uniq`, one stage at a time. A check script looks at your work 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-website-log-report](https://github.com/ask-codey/exercise-bash-the-website-log-report), 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:

- `site/access.log`: a week of the website's visits, one a line, in the same layout as the log in *Columns and Totals: awk*.
- `site/orders.csv`: the website's orders from September to November, with a header line.
- `site/pages/`: three of the website's pages, with the old phone number on them.
- `answers.txt`: five questions, each with a numbered line for your answer.
- `check.bats`: the check. You don't need to change it.

## What to do

Open a terminal and `cd` into the exercise folder (the one with `answers.txt` in it). Look at the data's shape first, with `head -n 3 site/access.log` and `head -n 3 site/orders.csv`. Then work through the jobs:

1. **Change the phone number.** The number changed from `555-0142` to `555-0187`. Change it on every page in `site/pages/`, in place, keeping a `.bak` backup of each page, as in *Find and Replace in a Stream: sed*. Run the command without `-i` first and read what it prints.
2. **Save the top pages.** Write `top-pages.txt` in the exercise folder: the five most visited pages in `site/access.log`, each with its count, biggest first, the way `uniq -c` and `sort -rn` print them. Build it a stage at a time, as in *Building a Pipeline a Step at a Time*, and save it with `>` once the output is right.
3. **Answer the questions** in `answers.txt`. Open it in nano (`nano answers.txt`), write each answer after its `)`, and save. The file starts like this:

```text
# Example: what is the status code of the first visit in site/access.log?
# 0) 200

# 1. How many visits in the week got the status code 404 (no such page)?
1)
```

## 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 *site/pages/contact.html still has the old number, 555-0142, on this line: … Is there a g at the end of your s command? Without it, sed changes only the first match on each line.*

## Hints

- **Look before you change.** `sed 's/old/new/g'` on the pages prints what they would become. When that looks right, run the same command with `-i.bak`. If a page goes wrong, `mv` its `.bak` file back over it and try again.
- **One line can hold the number twice.** That's what the `g` is for.
- **Know your fields.** In the log, the address is `$1`, the page `$7` and the status code `$9`. The orders need `awk -F,`, and their total is `$5`.
- **Count with a pattern you know by heart.** `sort | uniq -c | sort -rn` counts each line and puts the biggest count first; `head -n 1` keeps the winner.
- **The date is inside the fourth field**, after a `[`: `[08/Nov/2026:07:00:13`. `cut -d'[' -f2` and then `cut -d: -f1` leave only the day.
- **October's sales:** the sales-per-month line from *Columns and Totals: awk* prints every month's total.

## When you're done

Every check passes:

```text
check.bats
 ✓ the site folder is still here
 ✓ every page has the new phone number, and none has the old one
 ✓ each page kept a .bak backup with the old number
 ✓ only the phone number changed on each page
 ✓ top-pages.txt holds the five most visited pages, biggest first
 ✓ 1) how many visits got a 404
 ✓ 2) the page visited most
 ✓ 3) the address that failed to log in most often
 ✓ 4) the day with the most visits
 ✓ 5) the total sales in October

10 tests, 0 failures
```

Now look back at your pipelines. Each answered one question, and you built each by hand. What would it take to run all of them again next week, on next week's log, with one command? Module 5, *Scripts Are Applications*, is where that question gets its answer.

## 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-website-log-report`), 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-website-log-report.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-website-log-report.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-website-log-report`, 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

Changing a value across a website's files and turning a raw log into answers are everyday jobs for web developers and the people who keep websites running, and you did both without opening a single web page or log in an editor.

## Key terms

- [sed](https://www.ask-codey.com/glossary/sed)
- [awk](https://www.ask-codey.com/glossary/awk)
- [Pipe](https://www.ask-codey.com/glossary/pipe-unix)
- [Status Code](https://www.ask-codey.com/glossary/status-code)
- [Log File](https://www.ask-codey.com/glossary/log-file)

## Related

- [Find and Replace in a Stream: sed](https://www.ask-codey.com/lessons/bash-sed)
- [Columns and Totals: awk](https://www.ask-codey.com/lessons/bash-awk)
- [Building a Pipeline a Step at a Time](https://www.ask-codey.com/lessons/bash-building-a-pipeline)

Source: https://www.ask-codey.com/lessons/exercise-bash-the-website-log-report
