Computing FoundationsThe Command Line › Day 8

Hands-on lab — Day 8: Meet the Terminal: Shells, Prompts, and Commands

Commands

Setup

cd labs/sections/computing-foundations/day-008-meet-the-terminal-shells-prompts-and

Run

bash examples/shell_tour.sh
bash starter/shell_tour.sh

Test

bash tests/run_tests.sh

File tree

examples/shell_tour.sh
expected-output/FIELDS.md
expected-output/sample-macos.txt
metadata.yml
README.md
requirements/README.md
security.md
starter/shell_tour.sh
starter/shell-session-worksheet.md
tests/run_tests.sh
troubleshooting.md

Lab README

Day 008 lab — Your First Shell Session

Lesson

Purpose

Day 8's lesson explains what a terminal, a shell, and a command are. This lab makes it concrete: you run a short tour of your own shell that reveals which shell is running, what your prompt string is, and what a handful of everyday commands (pwd, echo, date, whoami, history, type) actually print. Then you fill in a worksheet describing your session in your own words.

Learning objectives

  • Discover which shell you are running and your default shell (echo $0, echo $SHELL, ps -p $$).
  • See your raw prompt string (echo "$PS1") and understand what it is.
  • Run and read the output of pwd, echo, date, and whoami.
  • Recall recent commands with history | tail and identify a command with type.
  • Complete a shell script by filling in five well-specified exercises, then verify it with an automated test.

Prerequisites

  • The Day 8 lesson (read it first — it explains every term this lab shows you).
  • A terminal: Terminal.app (macOS), any terminal (Linux), or PowerShell/WSL (Windows).
  • No programming experience required; every command is given and explained.

Supported operating systems

  • macOS — fully supported (tested on macOS with Apple Silicon, default shell zsh).
  • Linux — fully supported (any distribution with bash and standard utilities).
  • Windows — run the scripts unmodified inside WSL, or type the individual commands from the lesson's hands-on section in PowerShell where equivalents exist.

Hardware requirements

Any computer made in roughly the last 15 years. The lab only reads session information; it needs no minimum RAM, disk, or GPU.

Required software

  • bash (3.2 or newer — preinstalled on macOS and Linux).
  • Standard OS utilities only: ps, pwd, echo, date, whoami, sed, tail. All preinstalled.

Free and open-source options

Everything in this lab is free: bash and every command used are open-source or ship with your OS. No account, API key, or purchase is needed.

Installation

None. Clone the repository (or copy this directory) and you are ready:

cd labs/sections/computing-foundations/day-008-meet-the-terminal-shells-prompts-and

File structure

day-008-meet-the-terminal-shells-prompts-and/
├── README.md                          ← you are here
├── metadata.yml                       ← machine-readable lab metadata
├── starter/
│   ├── shell_tour.sh                  ← YOUR working file (5 exercises)
│   └── shell-session-worksheet.md     ← worksheet for the practice assignment
├── examples/
│   └── shell_tour.sh                  ← completed reference implementation
├── tests/
│   └── run_tests.sh                   ← automated checks
├── expected-output/
│   ├── sample-macos.txt               ← real captured run (macOS, zsh default)
│   └── FIELDS.md                      ← required sections on every platform
├── requirements/
│   └── README.md                      ← dependency statement (none beyond the OS)
├── troubleshooting.md
└── security.md

How to run

From this directory:

## 1. See the finished result first
bash examples/shell_tour.sh

## 2. Your task: complete the five exercises in the starter, then run it
bash starter/shell_tour.sh

## 3. Check your work
bash tests/run_tests.sh

What the commands do

  • bash examples/shell_tour.sh — runs the reference tour: prints the running shell (echo $0), your default shell (echo $SHELL), the shell process (ps -p $$), your prompt string (echo "$PS1"), then pwd, echo hello, date, whoami, a history | tail sample, and type echo.
  • bash starter/shell_tour.sh — the same skeleton with five values set to unknown; each exercise comment names the exact command to use. Edit the file in any text editor and replace each unknown assignment with the command in $(...) form.
  • bash tests/run_tests.sh — runs both scripts and checks: exit code 0, the tour header/footer, every required section, that echo hello prints hello and type echo reports a shell builtin; and (once your starter has no unknown left) that the five exercise fields hold real values.

Expected output

See expected-output/sample-macos.txt — a real captured run. A shortened view:

=== Shell Tour ===
Generated on: 2026-07-12

--- Which shell am I running? ---
Current shell (echo $0): examples/shell_tour.sh
Default shell (echo $SHELL): /bin/zsh
Shell process (ps -p $$):
      PID TTY           TIME CMD
    12117 ??         0:00.00 bash examples/shell_tour.sh
...
Echo demo (echo hello): hello
Date (date): Sun Jul 12 13:32:42 IST 2026
User (whoami): you
...
type echo: echo is a shell builtin
=== End of tour ===

Your values will differ — that is the point. Note that echo $0 inside a script prints the script's name; run echo $0 directly in your terminal to see your interactive shell (e.g. -zsh). expected-output/FIELDS.md lists exactly which sections must appear on every platform.

Validation steps

  1. Run bash starter/shell_tour.sh — it must exit without errors.
  2. Confirm no exercise line reads unknown (the five fields you filled in).
  3. Confirm the tour prints your shell, your default shell, pwd, date, and whoami.
  4. Run the tests (next section) — all checks must pass.

Tests

bash tests/run_tests.sh

Expected final line: 35 checks, 0 failure(s). (20 strict checks against the reference tour, and 15 structural checks against your starter — which become 20 strict checks once you have replaced every unknown). The command exits 0 on success and non-zero on any failure, so it can run in CI.

Cleanup

Nothing to clean up: the scripts only read session information and write nothing outside their own console output. To reset your work, restore the starter file from git: git checkout -- starter/shell_tour.sh.

Troubleshooting

See troubleshooting.md for the full list (empty $PS1, empty history, $0 showing the script name, WSL notes).

Security notes

See security.md. Short version: the scripts run no network calls, need no elevated privileges, and expose only local session facts — but a shell profile is mildly identifying, so think before pasting it publicly.

Extension exercises

  1. Run echo $0 and echo "$PS1" directly in your interactive terminal (not through the script) and compare the values with the script's output — explain the difference in one sentence.
  2. Start a different shell by hand (bash, then later exit) and re-run echo $0 inside it; confirm $SHELL is unchanged while $0 now names the shell you started.
  3. Open man ls, read the descriptions of -l and -a, quit with q, then run ls -la / and confirm you can label the command, options, and argument.
  • Previous day: Day 7 — the final lesson of Week 1.
  • Next day: Day 9 — the next lesson of Week 2 (to be written).

Expected output

FIELDS.md

# Required tour sections (all platforms)

A correct run of `shell_tour.sh` prints, in order, these labelled sections:

1. `=== Shell Tour ===`
2. `Generated on: YYYY-MM-DD`
3. `Current shell (echo $0): <shell or script name>`
4. `Default shell (echo $SHELL): <path, e.g. /bin/zsh or /bin/bash>`
5. `Shell process (ps -p $$):` followed by the current shell's process row
6. `Prompt string (echo "$PS1"): <template, or an "empty" note in non-interactive runs>`
7. `Working directory (pwd): <an absolute path>`
8. `Echo demo (echo hello): hello`
9. `Date (date): <current date and time>`
10. `User (whoami): <your username>`
11. `Recent command history (history | tail)` section (may be empty in a script)
12. `type echo: echo is a shell builtin`
13. `=== End of tour ===`

`sample-macos.txt` in this directory is a real captured run (macOS, Apple
Silicon, zsh as the default shell, 2026-07-12).

## Platform and context notes (real, not fabricated)

- **`echo $0` inside a script prints the script's path** (e.g.
  `examples/shell_tour.sh`), because `$0` is the name of the *program running
  now* — which, for a script, is the script. Run `echo $0` **directly in your
  interactive terminal** and it prints your shell instead, such as `-zsh` or
  `bash`. Both are correct; they answer slightly different questions.
- **`$PS1` is usually empty in a non-interactive script**, so the tour prints a
  note rather than a value. Run `echo "$PS1"` in your interactive shell to see
  the real prompt template (for example `%n@%m %1~ %#` in zsh).
- **`history | tail` is often empty inside a script**, because history is a
  feature of interactive shells. Run `history | tail` directly in your terminal
  to see your logged commands.
- **Linux vs macOS:** the shape is identical. `ps -p $$` formats its columns
  slightly differently, `date` follows your locale, and if your default shell is
  bash the `$SHELL` line reads `/bin/bash`. No field is fabricated here; only the
  exact strings differ by machine.

sample-macos.txt

=== Shell Tour ===
Generated on: 2026-07-12

--- Which shell am I running? ---
Current shell (echo $0): examples/shell_tour.sh
Default shell (echo $SHELL): /bin/zsh
Shell process (ps -p $$):
      PID TTY           TIME CMD
    12117 ??         0:00.00 bash examples/shell_tour.sh

--- What does my prompt look like? ---
Prompt string (echo "$PS1"): (empty in this non-interactive run — try it in your interactive shell)

--- A handful of everyday commands ---
Working directory (pwd): <repo>/labs/sections/computing-foundations/day-008-meet-the-terminal-shells-prompts-and
Echo demo (echo hello): hello
Date (date): Sun Jul 12 13:32:42 IST 2026
User (whoami): you

--- Recent command history (history | tail) ---
    (no history in this non-interactive run — run 'history | tail' in your terminal)

--- What kind of thing is 'echo'? ---
type echo: echo is a shell builtin

=== End of tour ===

Source files

examples/shell_tour.sh (2230 bytes)
#!/usr/bin/env bash
# Day 008 lab — completed reference implementation: a guided tour of your shell.
#
# Prints, in clearly labelled sections: which shell is running, your default
# shell, the shell process, your prompt string, and the output of a handful of
# everyday commands (pwd, echo, date, whoami, history, type). Every command is
# read-only — it inspects your session and changes nothing.
#
# Works in bash and zsh on macOS and Linux. Run it with:
#   bash examples/shell_tour.sh
set -u

echo "=== Shell Tour ==="
echo "Generated on: $(date '+%Y-%m-%d')"

echo
echo "--- Which shell am I running? ---"
# $0 is the name of the shell (or script) currently running.
echo "Current shell (echo \$0): $0"
# $SHELL is your DEFAULT login shell, which may differ from the one running now.
echo "Default shell (echo \$SHELL): ${SHELL:-unknown}"
# ps -p $$ shows the process of the current shell ($$ is its process id).
echo "Shell process (ps -p \$\$):"
ps -p $$ | sed 's/^/    /'

echo
echo "--- What does my prompt look like? ---"
# PS1 is the prompt-string template. In a non-interactive script it is often
# empty; run 'echo \"\$PS1\"' directly in your interactive shell to see it.
if [ -n "${PS1:-}" ]; then
  echo "Prompt string (echo \"\$PS1\"): ${PS1}"
else
  echo "Prompt string (echo \"\$PS1\"): (empty in this non-interactive run — try it in your interactive shell)"
fi

echo
echo "--- A handful of everyday commands ---"
echo "Working directory (pwd): $(pwd)"
echo "Echo demo (echo hello): $(echo hello)"
echo "Date (date): $(date)"
echo "User (whoami): $(whoami)"

echo
echo "--- Recent command history (history | tail) ---"
# 'history' is a shell built-in; in a non-interactive script the list may be
# empty. This is expected — the point is that your INTERACTIVE shell records it.
hist_output="$(history 2>/dev/null | tail || true)"
if [ -n "${hist_output}" ]; then
  echo "${hist_output}" | sed 's/^/    /'
else
  echo "    (no history in this non-interactive run — run 'history | tail' in your terminal)"
fi

echo
echo "--- What kind of thing is 'echo'? ---"
# 'type' tells you whether a name is a built-in, a program on disk, or an alias.
echo "type echo: $(type echo)"

echo
echo "=== End of tour ==="
metadata.yml (575 bytes)
lesson_id: D008
day: 8
kind: command-line-inspection
languages: [bash]
setup_commands:
  - cd labs/sections/computing-foundations/day-008-meet-the-terminal-shells-prompts-and
run_commands:
  - bash examples/shell_tour.sh
  - bash starter/shell_tour.sh
test_commands:
  - bash tests/run_tests.sh
cleanup_commands:
  - 'git checkout -- starter/shell_tour.sh  # optional: reset your work'
requires_network: false
requires_api_key: false
estimated_minutes: 30
last_executed: '2026-07-12'
executed_on: 'macOS (Apple Silicon), bash tests/run_tests.sh → 35 checks, 0 failure(s).'
requirements/README.md (558 bytes)
# Dependencies — Day 008 lab

**None beyond a POSIX shell.** This lab intentionally has zero installable
dependencies:

- `bash` ≥ 3.2 (preinstalled on macOS and every mainstream Linux distribution)
- Standard OS utilities: `ps`, `pwd`, `echo`, `date`, `whoami`, `sed`, `tail`,
  and the shell built-ins `history` and `type` — all part of the base system.

There is deliberately no `requirements.txt`/`package.json` here; a first
terminal lab must run on a factory-fresh machine. Later labs declare their
Python or Node dependencies in this directory.
starter/shell_tour.sh (2389 bytes)
#!/usr/bin/env bash
# Day 008 lab — YOUR shell tour.
#
# This starter already prints the section headers and the demonstration lines
# (the shell process, your prompt string, a history sample, and 'type echo').
# Your job is the five numbered exercises below: replace each `unknown` with the
# single command shown in the comment, wrapped in $(...) so its output is
# captured. The finished reference version is in examples/shell_tour.sh — try it
# yourself first, then run this, then run the tests.
set -u

echo "=== Shell Tour ==="
echo "Generated on: $(date '+%Y-%m-%d')"

echo
echo "--- Which shell am I running? ---"

# Exercise 1: set current_shell using the command:  echo $0
#   ($0 is the name of the shell or script running right now.)
current_shell="unknown"

# Exercise 2: set default_shell using the command:  echo $SHELL
#   ($SHELL is your DEFAULT login shell — it may differ from the one running now.)
default_shell="unknown"

echo "Current shell (echo \$0): ${current_shell}"
echo "Default shell (echo \$SHELL): ${default_shell}"
echo "Shell process (ps -p \$\$):"
ps -p $$ | sed 's/^/    /'

echo
echo "--- What does my prompt look like? ---"
if [ -n "${PS1:-}" ]; then
  echo "Prompt string (echo \"\$PS1\"): ${PS1}"
else
  echo "Prompt string (echo \"\$PS1\"): (empty in this non-interactive run — try it in your interactive shell)"
fi

echo
echo "--- A handful of everyday commands ---"

# Exercise 3: set here using the command:  pwd
#   (pwd prints the working directory — the folder the shell is standing in.)
here="unknown"

# Exercise 4: set today using the command:  date
#   (date takes no options and no arguments; it prints the current date/time.)
today="unknown"

# Exercise 5: set me using the command:  whoami
#   (whoami prints your username — the identity your commands act as.)
me="unknown"

echo "Working directory (pwd): ${here}"
echo "Echo demo (echo hello): $(echo hello)"
echo "Date (date): ${today}"
echo "User (whoami): ${me}"

echo
echo "--- Recent command history (history | tail) ---"
hist_output="$(history 2>/dev/null | tail || true)"
if [ -n "${hist_output}" ]; then
  echo "${hist_output}" | sed 's/^/    /'
else
  echo "    (no history in this non-interactive run — run 'history | tail' in your terminal)"
fi

echo
echo "--- What kind of thing is 'echo'? ---"
echo "type echo: $(type echo)"

echo
echo "=== End of tour ==="
starter/shell-session-worksheet.md (1617 bytes)
# My First Shell Session — Day 008 worksheet

Fill in every value from your own machine using the lab script or the individual
commands from the lesson's hands-on section. Keep this file — later lessons build
on your comfort at the prompt.

## My shell

| Field | Your value | Command you used |
| ----------------------------- | ---------- | ---------------- |
| Shell running right now       |            | `echo $0` (or `ps -p $$`) |
| My default login shell        |            | `echo $SHELL` |
| My raw prompt string (`$PS1`) |            | `echo "$PS1"` |

## Three commands I ran

For each command, write the exact command you typed, exactly what it printed
(one line is fine), and a one-sentence explanation of what it did — naming which
parts were the command, options, and arguments.

| # | Exact command | What it printed | What it did (and its command / options / arguments) |
| - | ------------- | --------------- | --------------------------------------------------- |
| 1 |               |                 |                                                     |
| 2 |               |                 |                                                     |
| 3 |               |                 |                                                     |

## How my command travelled through the read-eval-print loop

Write two or three sentences: name your shell, then trace one command you ran
from your keystrokes through the shell reading and parsing the line, finding and
running the program, printing the output, and the prompt returning.

## One thing that surprised me

One or two sentences.
tests/run_tests.sh (3248 bytes)
#!/usr/bin/env bash
# Tests for the Day 008 lab. Run from the lab directory:
#   bash tests/run_tests.sh
#
# Verifies that the completed reference tour prints every required section with
# real (non-"unknown") values, and — if the learner has finished the starter —
# checks their version the same way.
set -u

lab_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
failures=0
checks=0

check() {
  local label="$1" ok="$2"
  checks=$((checks + 1))
  if [ "${ok}" = "yes" ]; then
    echo "  ok: ${label}"
  else
    echo "  FAIL: ${label}"
    failures=$((failures + 1))
  fi
}

run_tour_checks() {
  local script="$1" strict="$2" output
  echo "Testing ${script} ..."
  if ! output="$(bash "${script}" 2>&1)"; then
    check "script exits successfully" "no"
    echo "${output}" | sed 's/^/    /'
    return
  fi
  check "script exits successfully" "yes"
  echo "${output}" | grep -q '^=== Shell Tour ===$' && check "prints tour header" "yes" || check "prints tour header" "no"
  echo "${output}" | grep -q '^=== End of tour ===$' && check "prints tour footer" "yes" || check "prints tour footer" "no"
  # Required labelled sections (the tour must show each of these).
  for marker in \
    "Current shell (echo \$0):" \
    "Default shell (echo \$SHELL):" \
    "Shell process (ps -p \$\$):" \
    "Prompt string (echo \"\$PS1\"):" \
    "Working directory (pwd):" \
    "Echo demo (echo hello):" \
    "Date (date):" \
    "User (whoami):" \
    "Recent command history (history | tail)" \
    "type echo:"; do
    if echo "${output}" | grep -qF "${marker}"; then
      check "prints section '${marker}'" "yes"
    else
      check "prints section '${marker}'" "no"
    fi
  done
  # The echo demo must actually print the word it echoed.
  echo "${output}" | grep -qF "Echo demo (echo hello): hello" && check "echo hello prints 'hello'" "yes" || check "echo hello prints 'hello'" "no"
  # 'type echo' should identify echo as a shell builtin.
  echo "${output}" | grep -qi "echo is a shell builtin" && check "type echo reports a shell builtin" "yes" || check "type echo reports a shell builtin" "no"

  if [ "${strict}" = "strict" ]; then
    # In a finished tour, the five exercise fields must not read 'unknown'.
    for field in \
      "Current shell (echo \$0): unknown" \
      "Default shell (echo \$SHELL): unknown" \
      "Working directory (pwd): unknown" \
      "Date (date): unknown" \
      "User (whoami): unknown"; do
      if echo "${output}" | grep -qF "${field}"; then
        check "field is filled in, not 'unknown' (${field%%:*})" "no"
      else
        check "field is filled in, not 'unknown' (${field%%:*})" "yes"
      fi
    done
  fi
}

run_tour_checks "${lab_dir}/examples/shell_tour.sh" strict

# The starter ships with 'unknown' values on purpose; once the learner has
# replaced them all, hold their script to the same strict standard.
if grep -q '="unknown"' "${lab_dir}/starter/shell_tour.sh"; then
  echo "Note: starter/shell_tour.sh still has unfilled exercises — testing structure only."
  run_tour_checks "${lab_dir}/starter/shell_tour.sh" lenient
else
  run_tour_checks "${lab_dir}/starter/shell_tour.sh" strict
fi

echo
echo "${checks} checks, ${failures} failure(s)."
[ "${failures}" -eq 0 ]

Troubleshooting

Troubleshooting — Day 008 lab

echo $0 prints the script name, not my shell

That is correct. $0 is the name of the program running right now; inside a script that program is the script, so you see examples/shell_tour.sh or starter/shell_tour.sh. To see your interactive shell, type echo $0 directly in your terminal (not through the script) — it will print something like -zsh or bash.

echo "$PS1" prints an empty line (or the tour says "empty")

PS1, the prompt-string template, is normally only set in interactive shells, so a script usually sees it empty — the tour prints a note instead of a value. Run echo "$PS1" in your interactive terminal to see the real template (for example %n@%m %1~ %# in zsh). Keep the double quotes; without them the shell may mangle the special characters.

history | tail shows nothing

history is a feature of interactive shells; a script often starts with an empty history list, which is why the tour prints a placeholder note. Run history | tail directly in your terminal after running a few commands and you will see your logbook.

Permission denied when running the script

You don't need to make it executable — run it through bash explicitly: bash starter/shell_tour.sh. If you prefer ./starter/shell_tour.sh, first run chmod +x starter/shell_tour.sh.

Tests fail on a field that is still unknown

That check is telling you an exercise is unfinished — search the starter for "unknown" and complete the remaining assignments, replacing each with the command named in its comment, wrapped in $(...).

ps -p $$ looks different from the sample

Column formatting and the TTY value vary by OS and by how you launched the shell; the important part is that a single process row for your current shell appears. This is expected and not a failure.

Windows: bash is not recognized

Use WSL (wsl --install, then open Ubuntu and run the scripts unmodified), or skip the script and type the individual commands from the lesson's hands-on section in your terminal, filling the worksheet manually.

Security notes

Security notes — Day 008 lab

  • What the scripts do: read information about your current shell session (echo $0, echo $SHELL, ps -p $$, echo "$PS1") and run a few read-only commands (pwd, echo, date, whoami, history, type). They make no network connections, write no files, and change no settings.
  • Privileges: everything runs as your normal user. Nothing in this lab needs sudo; if any tutorial ever asks you to sudo a script you haven't read, that is your cue to stop and read it — a habit this course reinforces, because a shell runs whatever you type with your full privileges and asks no questions.
  • Privacy: a shell profile (username, working directory, shell version) is mildly identifying. Sharing it in a class forum is normally fine; avoid posting profiles of employer-managed machines. Remember that your shell records a history file on disk — so never type passwords or secret keys directly on a command line, where they would be logged in plain text.
  • Reading before running: both scripts are short and commented — read them first. Running unread shell scripts from the internet is one of the most common ways developers get compromised; the course's rule is that every lab script is small enough to read and understand before executing.