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
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:
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, 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.shandfetch.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 wayjq .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:
chmod +x report.sh fetch.sh
nano report.sh
report.sh FORECAST_FILEchecks that the file is there (if not, it says so and stops with exit code 1). Then it printsWeather report forand today's date as year-month-day; one line for each of the forecast's first four periods, such asToday: 58 F, Mostly Sunny; and a line such asUmbrella: Fridayfor every period with a chance of rain of 50 or more, or the one lineUmbrella: not neededwhen there's none.fetch.sh ADDRESS FILEdownloads the address withcurland 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 printsSaved FILE; when it fails, it says so, leaves the file exactly as it was, and stops with exit code 1.- Save today's report. When the checks for
report.shpass, save its report forsaved/forecast.jsoninreports/, namedreport-and today's date, such asreports/report-2026-11-09.txt. Letdatemake the name.
With the internet, you can get a fresh forecast before step 3, once fetch.sh works:
./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:
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
jqfilter at the prompt onsaved/forecast.json, as in JSON with jq, before you put it in the script:.properties.periods[], then-rand"\( )"to build each line, thenselectfor the rain. - The first four lines:
head -n 4keeps 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
curlfail on an error answer, and what||orifcan do when it does.
When you're done
Every check passes:
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.
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.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-todays-weather-report.git git push -u origin mainIf 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-todays-weather-report.git git add . git commit -m "My solution" git push -u origin mainPaste 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.