# Exercise: Today's Weather Report

Write two small tools, a script that turns a saved weather forecast into a short daily report with jq and date, and one that downloads a fresh forecast with curl without ever losing the saved one, then let a check script tell you what's done.

Journeyman · Unix · Linux · Updated November 10, 2026

Every morning you'd like one short report before you leave: today's date, the weather for the next two days, and whether to pack an umbrella this week. Weather apps bury that under ads and radar maps; a script can print exactly what you want. You'll write it as two small tools: `report.sh`, which turns a saved forecast into the report, and `fetch.sh`, which downloads a fresh forecast without ever losing the saved one. Then you'll save today's report under today's date. A check script tries each tool on made-up forecasts of its own and 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 report reads the forecast with **jq** (*JSON with jq*), and the check runs with **bats**, a small program that runs checks written for bash. `curl` is already there. If `jq --version` or `bats --version` doesn't print a version number yet, install them:

```bash
sudo apt install jq bats       # Ubuntu, and Ubuntu in WSL
brew install jq 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-todays-weather-report](https://github.com/ask-codey/exercise-bash-todays-weather-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. 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:

- `report.sh` and `fetch.sh`: the two scripts. Each starts with a comment that says exactly what it must do. These are the files you write.
- `saved/forecast.json`: a real forecast for New York's Central Park from the US National Weather Service, the same one *JSON with jq* uses, laid out the way `jq .` prints it.
- `reports/`: where your dated reports go.
- `check.bats`: the check. You don't need to change it.

## What to do

Open a terminal in the exercise folder, make the scripts runnable (*Your First Script*), and open the first one in nano:

```bash
chmod +x report.sh fetch.sh
nano report.sh
```

1. **`report.sh FORECAST_FILE`** checks that the file is there (if not, it says so and stops with exit code 1). Then it prints `Weather report for` and today's date as year-month-day; one line for each of the forecast's first four periods, such as `Today: 58 F, Mostly Sunny`; and a line such as `Umbrella: Friday` for every period with a chance of rain of 50 or more, or the one line `Umbrella: not needed` when there's none.
2. **`fetch.sh ADDRESS FILE`** downloads the address with `curl` and saves it as the file, sending a User-Agent with your script's name and your email address. It fails on an error answer such as 404 instead of saving the error page. When it works, it prints `Saved FILE`; when it fails, it says so, leaves the file exactly as it was, and stops with exit code 1.
3. **Save today's report.** When the checks for `report.sh` pass, save its report for `saved/forecast.json` in `reports/`, named `report-` and today's date, such as `reports/report-2026-11-09.txt`. Let `date` make the name.

With the internet, you can get a fresh forecast before step 3, once `fetch.sh` works:

```bash
./fetch.sh 'https://api.weather.gov/gridpoints/OKX/34,45/forecast' saved/forecast.json
```

The fresh copy has more in it than the saved one, and your report reads it the same way.

## Check your work

From the exercise folder:

```bash
bats check.bats
```

At first almost every check fails. That's expected: each job you finish turns its checks into a ✓. The check tries your scripts on made-up forecasts of its own, in a throwaway folder, and needs no internet; only the last check looks at your `reports/` folder. A failing check says what to look at, for example *For a forecast in Celsius, the second line should be: Today: 21 C, Sunny. Take the unit from .temperatureUnit; don't write F into the script.*

## Hints

- **Try the filter first.** Work out each `jq` filter at the prompt on `saved/forecast.json`, as in *JSON with jq*, before you put it in the script: `.properties.periods[]`, then `-r` and `"\( )"` to build each line, then `select` for the rain.
- **The first four lines:** `head -n 4` keeps the first four lines of whatever is piped into it.
- **No rain at all:** keep the rainy names in a variable with `$( )` and test whether it's empty with `[[ -z $rainy ]]` (*If This, Then That: if and [[ ]]*).
- **The date** in the report and in the file name is the same `$(date +%F)` from *Dates and Times*.
- **A failed download** must not touch the saved file. *Talking to the Web: curl* shows which option makes `curl` fail on an error answer, and what `||` or `if` can do when it does.

## When you're done

Every check passes:

```text
check.bats
 ✓ the scripts, the saved forecast and jq are here
 ✓ 1) report.sh starts with today's date
 ✓ 2) report.sh prints the first four periods
 ✓ 3) report.sh uses the forecast's own unit
 ✓ 4) report.sh lists every period with a chance of rain of 50 or more
 ✓ 5) report.sh says when no umbrella is needed
 ✓ 6) report.sh stops with an error when the forecast file isn't there
 ✓ 7) report.sh reads the forecast with jq
 ✓ 8) fetch.sh saves what it downloads
 ✓ 9) fetch.sh keeps the saved copy when the download fails
 ✓ 10) fetch.sh uses curl -f and sends a User-Agent
 ✓ 11) a dated report is saved in reports/

12 tests, 0 failures
```

Now look back at the two scripts. Run every morning, one after the other, they make a weather service of your own. Which one line would you add to `report.sh` to list the nights colder than 40 degrees, and where would it go?

## 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-todays-weather-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-todays-weather-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-todays-weather-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-todays-weather-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

Fetching data, picking out what matters and stamping it with the date is the shape of most scripts that run every morning without you, from a weather report to a server's health check.

## Key terms

- [jq](https://www.ask-codey.com/glossary/jq)
- [JSON](https://www.ask-codey.com/glossary/json)
- [curl](https://www.ask-codey.com/glossary/curl)
- [Status Code](https://www.ask-codey.com/glossary/status-code)
- [date](https://www.ask-codey.com/glossary/date)

## Related

- [JSON with jq](https://www.ask-codey.com/lessons/bash-jq)
- [Talking to the Web: curl](https://www.ask-codey.com/lessons/bash-curl)
- [Dates and Times](https://www.ask-codey.com/lessons/bash-dates)
- [CSV Files in Bash, and Their Limits](https://www.ask-codey.com/lessons/bash-csv-files)

Source: https://www.ask-codey.com/lessons/exercise-bash-todays-weather-report
