Computing FoundationsInside the Machine › Day 1

Hands-on lab — Day 1: How a Computer Works: From Transistors to Programs

Commands

Setup

cd labs/sections/computing-foundations/day-001-how-a-computer-works-from-transistors

Run

bash examples/inspect_my_computer_completed.sh
bash starter/inspect_my_computer.sh

Test

bash tests/run_tests.sh

File tree

examples/inspect_my_computer_completed.sh
expected-output/FIELDS.md
expected-output/sample-macos.txt
metadata.yml
README.md
requirements/README.md
security.md
starter/inspect_my_computer.sh
starter/machine-profile-template.md
tests/run_tests.sh
troubleshooting.md

Lab README

Day 001 lab — Inspect Your Own Computer

Lesson

Purpose

Day 1's lesson explains the layers between physics and software. This lab makes it concrete: you interrogate your own machine from the terminal and produce a real "machine profile" — the CPU, cores, RAM, disk, and OS you will rely on for the next 364 days.

Learning objectives

  • Run commands in a terminal and read their output confidently.
  • Measure your machine's CPU model, core count, RAM, free disk, and OS version.
  • Convert bytes to GiB and explain the difference between memory (RAM) and storage (disk).
  • Complete a small shell script by filling in five well-specified exercises.
  • Run an automated test script and interpret its pass/fail output.

Prerequisites

  • The Day 1 lesson (read it first — it explains every concept this lab measures).
  • 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).
  • Linux — fully supported (any distribution with lscpu, nproc, /proc/meminfo).
  • Windows — use the PowerShell alternatives in the lesson's hands-on section (Get-ComputerInfo), or run the scripts unmodified inside WSL.

Hardware requirements

Any computer made in roughly the last 15 years. The lab only reads system 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: sysctl, sw_vers, df (macOS); lscpu, nproc, df (Linux). 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 — this is true of every lab in the course wherever possible, and any exception is labelled.

Installation

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

cd labs/sections/computing-foundations/day-001-how-a-computer-works-from-transistors

File structure

day-001-how-a-computer-works-from-transistors/
├── README.md                                 ← you are here
├── metadata.yml                              ← machine-readable lab metadata
├── starter/
│   ├── inspect_my_computer.sh                ← YOUR working file (5 exercises)
│   └── machine-profile-template.md           ← worksheet for the practice assignment
├── examples/
│   └── inspect_my_computer_completed.sh      ← completed reference implementation
├── tests/
│   └── run_tests.sh                          ← automated checks
├── expected-output/
│   ├── sample-macos.txt                      ← real captured run (macOS, Apple Silicon)
│   └── FIELDS.md                             ← required fields 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/inspect_my_computer_completed.sh

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

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

What the commands do

  • bash examples/inspect_my_computer_completed.sh — runs the reference script: detects your OS (uname -s), then uses sysctl/sw_vers (macOS) or lscpu//proc/meminfo//etc/os-release (Linux) to print your CPU model, core count, RAM (converted from bytes to GiB by dividing by 1073741824), free disk on / (df -h /), and OS version.
  • bash starter/inspect_my_computer.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, header/footer lines, all five profile fields present; and (once your starter has no unknown left) that every field has a real value and the core count is a positive integer.

Expected output

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

=== My Machine Profile ===
Generated on: 2026-07-12
Operating system kernel: Darwin
CPU model: Apple M4 Max
CPU cores: 14
RAM: 36 GiB (38654705664 bytes)
Free disk on /: 436Gi
OS version: macOS 26.5.1
=== End of profile ===

Your values will differ — that is the point. On Linux the kernel line reads Linux and the OS version comes from /etc/os-release (e.g. an Ubuntu or Fedora release name). expected-output/FIELDS.md lists exactly which fields must appear on every platform.

Validation steps

  1. Run bash starter/inspect_my_computer.sh — it must exit without errors.
  2. Confirm no line contains unknown.
  3. Confirm the RAM line shows both GiB and bytes, and the GiB number matches what your OS reports in its own settings UI (About This Mac / System Monitor).
  4. Run the tests (next section) — all checks must pass.

Tests

bash tests/run_tests.sh

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

Cleanup

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

Troubleshooting

See troubleshooting.md for the full list (command not found, permission messages, byte-conversion confusion, WSL notes).

Security notes

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

Extension exercises

  1. Add your CPU cache sizes to the profile (macOS: sysctl hw.l1dcachesize hw.l2cachesize; Linux: lscpu | grep -i cache) and note how much smaller than RAM they are.
  2. Compute how many float32 parameters (4 bytes each) fit in your RAM, and compare that with the parameter counts of AI models you have heard of.
  3. Extend the script to print GPU information (macOS: system_profiler SPDisplaysDataType; Linux: lspci | grep -i vga or nvidia-smi if present) and update the tests to check for your new field.
  • Previous day: none — this is Day 1.
  • Next day: Day 2 — The CPU: Fetch, Decode, Execute (labs/sections/computing-foundations/day-002-the-cpu-fetch-decode-execute/, to be written).

Expected output

FIELDS.md

# Required profile fields (all platforms)

A correct run of `inspect_my_computer.sh` prints, in order:

1. `=== My Machine Profile ===`
2. `Generated on: YYYY-MM-DD`
3. `Operating system kernel: Darwin` (macOS) or `Linux`
4. `CPU model: <non-empty string>`
5. `CPU cores: <positive integer>`
6. `RAM: <n> GiB (<bytes> bytes)`
7. `Free disk on /: <value with unit, e.g. 436Gi or 89G>`
8. `OS version: <non-empty string>` (macOS product version, or PRETTY_NAME from /etc/os-release)
9. `=== End of profile ===`

`sample-macos.txt` in this directory is a real captured run (macOS, Apple
Silicon, 2026-07-12). Linux output has the same shape; only the kernel line
and the OS version wording differ. No field may read `unknown` in a
completed solution.

sample-macos.txt

=== My Machine Profile ===
Generated on: 2026-07-12
Operating system kernel: Darwin
CPU model: Apple M4 Max
CPU cores: 14
RAM: 36 GiB (38654705664 bytes)
Free disk on /: 436Gi
OS version: macOS 26.5.1
=== End of profile ===

Source files

examples/inspect_my_computer_completed.sh (1332 bytes)
#!/usr/bin/env bash
# Day 001 lab — completed reference implementation.
# Prints a machine profile: CPU, cores, RAM, free disk, OS version.
# Supports macOS (Darwin) and Linux; Windows users use the PowerShell
# commands in the README (or run this under WSL).
set -euo pipefail

os="$(uname -s)"

echo "=== My Machine Profile ==="
echo "Generated on: $(date '+%Y-%m-%d')"
echo "Operating system kernel: ${os}"

if [ "${os}" = "Darwin" ]; then
  cpu_model="$(sysctl -n machdep.cpu.brand_string)"
  cpu_cores="$(sysctl -n hw.ncpu)"
  ram_bytes="$(sysctl -n hw.memsize)"
  os_version="macOS $(sw_vers -productVersion)"
elif [ "${os}" = "Linux" ]; then
  cpu_model="$(lscpu | sed -n 's/^Model name:[[:space:]]*//p' | head -n 1)"
  cpu_cores="$(nproc)"
  mem_kb="$(sed -n 's/^MemTotal:[[:space:]]*\([0-9]*\) kB/\1/p' /proc/meminfo)"
  ram_bytes="$((mem_kb * 1024))"
  os_version="$(sed -n 's/^PRETTY_NAME="\(.*\)"/\1/p' /etc/os-release)"
else
  echo "Unsupported OS for this script: ${os} (Windows users: see the README's PowerShell section)" >&2
  exit 1
fi

disk_free="$(df -h / | awk 'NR==2 {print $4}')"

echo "CPU model: ${cpu_model}"
echo "CPU cores: ${cpu_cores}"
echo "RAM: $((ram_bytes / 1073741824)) GiB (${ram_bytes} bytes)"
echo "Free disk on /: ${disk_free}"
echo "OS version: ${os_version}"
echo "=== End of profile ==="
metadata.yml (610 bytes)
lesson_id: D001
day: 1
kind: command-line-inspection
languages: [bash]
setup_commands:
  - cd labs/sections/computing-foundations/day-001-how-a-computer-works-from-transistors
run_commands:
  - bash examples/inspect_my_computer_completed.sh
  - bash starter/inspect_my_computer.sh
test_commands:
  - bash tests/run_tests.sh
cleanup_commands:
  - 'git checkout -- starter/inspect_my_computer.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 → 18 checks, 0 failures'
requirements/README.md (587 bytes)
# Dependencies — Day 001 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: `uname`, `date`, `df`, plus `sysctl`/`sw_vers` on
  macOS or `lscpu`/`nproc` and the `/proc/meminfo`, `/etc/os-release` files
  on Linux — all part of the base system.

There is deliberately no `requirements.txt`/`package.json` here; the first
lab must run on a factory-fresh machine. Later labs declare their Python or
Node dependencies in this directory.
starter/inspect_my_computer.sh (2005 bytes)
#!/usr/bin/env bash
# Day 001 lab — inspect your own computer from the command line.
#
# This starter script already detects your operating system and prints the
# report skeleton. Your job (README, "Your task" section) is to fill in each
# exercise below with the single command that prints the value, replacing the
# `unknown` assignments. The completed reference version is in
# examples/inspect_my_computer_completed.sh — try it yourself first.
set -euo pipefail

os="$(uname -s)"

echo "=== My Machine Profile ==="
echo "Generated on: $(date '+%Y-%m-%d')"
echo "Operating system kernel: ${os}"

if [ "${os}" = "Darwin" ]; then
  # Exercise 1 (macOS): set cpu_model using: sysctl -n machdep.cpu.brand_string
  cpu_model="unknown"
  # Exercise 2 (macOS): set cpu_cores using: sysctl -n hw.ncpu
  cpu_cores="unknown"
  # Exercise 3 (macOS): set ram_bytes using: sysctl -n hw.memsize
  ram_bytes="unknown"
  # Exercise 4 (macOS): set os_version using: sw_vers -productVersion
  os_version="unknown"
elif [ "${os}" = "Linux" ]; then
  # Exercise 1 (Linux): set cpu_model using: lscpu | grep 'Model name' (clean it with sed or awk)
  cpu_model="unknown"
  # Exercise 2 (Linux): set cpu_cores using: nproc
  cpu_cores="unknown"
  # Exercise 3 (Linux): set ram_bytes by reading MemTotal from /proc/meminfo (value is in kB — multiply by 1024)
  ram_bytes="unknown"
  # Exercise 4 (Linux): set os_version from PRETTY_NAME in /etc/os-release
  os_version="unknown"
else
  echo "Unsupported OS for this script: ${os} (Windows users: see the README's PowerShell section)" >&2
  exit 1
fi

# Exercise 5 (both): set disk_free for / using: df -h / (take the 'Avail' column of the data row)
disk_free="unknown"

echo "CPU model: ${cpu_model}"
echo "CPU cores: ${cpu_cores}"
if [ "${ram_bytes}" != "unknown" ]; then
  echo "RAM: $((ram_bytes / 1073741824)) GiB (${ram_bytes} bytes)"
else
  echo "RAM: unknown"
fi
echo "Free disk on /: ${disk_free}"
echo "OS version: ${os_version}"
echo "=== End of profile ==="
starter/machine-profile-template.md (1318 bytes)
# My Machine Profile — Day 001 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 —
Week 1's project (the Annotated Machine Teardown) builds on it.

| Field                     | Your value | Command you used |
| ------------------------- | ---------- | ---------------- |
| Date measured             |            |                  |
| CPU model                 |            |                  |
| CPU cores                 |            |                  |
| RAM (GiB)                 |            |                  |
| RAM (exact bytes)         |            |                  |
| Free disk on `/`          |            |                  |
| Total disk size           |            |                  |
| OS name and version       |            |                  |
| Kernel (`uname -s -r`)    |            |                  |

## My memory hierarchy, in my machine's real numbers

Write one paragraph: starting from your CPU's registers and ending at your
disk, describe each level of your machine's memory hierarchy, with the sizes
you measured where you have them. (The lesson's memory-hierarchy diagram is
your map; your numbers replace its labels.)

## One thing that surprised me

One or two sentences.
tests/run_tests.sh (2417 bytes)
#!/usr/bin/env bash
# Tests for the Day 001 lab. Run from the lab directory:
#   bash tests/run_tests.sh
#
# Verifies that the completed reference script produces a well-formed
# machine profile with real (non-"unknown") values, and — if the learner
# has finished the starter script — 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_profile_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 '^=== My Machine Profile ===$' && check "prints profile header" "yes" || check "prints profile header" "no"
  echo "${output}" | grep -q '^=== End of profile ===$' && check "prints profile footer" "yes" || check "prints profile footer" "no"
  for field in "CPU model:" "CPU cores:" "RAM:" "Free disk on /:" "OS version:"; do
    echo "${output}" | grep -q "^${field}" && check "prints '${field}'" "yes" || check "prints '${field}'" "no"
  done
  if [ "${strict}" = "strict" ]; then
    if echo "${output}" | grep -q "unknown"; then
      check "no field is left 'unknown'" "no"
    else
      check "no field is left 'unknown'" "yes"
    fi
    cores="$(echo "${output}" | sed -n 's/^CPU cores: //p')"
    case "${cores}" in
      '' | *[!0-9]*) check "CPU cores is a positive integer" "no" ;;
      *) check "CPU cores is a positive integer" "yes" ;;
    esac
  fi
}

run_profile_checks "${lab_dir}/examples/inspect_my_computer_completed.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/inspect_my_computer.sh"; then
  echo "Note: starter/inspect_my_computer.sh still has unfilled exercises — testing structure only."
  run_profile_checks "${lab_dir}/starter/inspect_my_computer.sh" lenient
else
  run_profile_checks "${lab_dir}/starter/inspect_my_computer.sh" strict
fi

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

Troubleshooting

Troubleshooting — Day 001 lab

sysctl: unknown oid or command not found: sw_vers

You are running the macOS commands on Linux (or vice versa). The script chooses the right branch automatically via uname -s; if you are typing commands manually, use the section of the lesson matching your OS.

command not found: lscpu (Linux)

Minimal containers and some distros omit util-linux. Install it (sudo apt install util-linux on Debian/Ubuntu) or read the model name directly: grep 'model name' /proc/cpuinfo | head -n 1.

Permission denied when running the script

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

The RAM number looks absurdly large

sysctl -n hw.memsize and /proc/meminfo report bytes and kB respectively. The script converts to GiB by dividing bytes by 1073741824 (1024³). If you see the raw number, you replaced the whole echo line instead of only the ram_bytes="unknown" assignment — restore the file (git checkout -- starter/inspect_my_computer.sh) and edit only the assignments.

My GiB value doesn't match the GB on the box my computer came in

Manufacturers use decimal gigabytes (10⁹ bytes); operating systems usually use binary gibibytes (2³⁰ bytes). 16 GB decimal ≈ 14.9 GiB binary. Both are "right"; the units differ. The Day 4 lesson (binary and data representation) covers this properly.

Tests fail with no field is left 'unknown'

That check is telling you an exercise is still unfinished — search the starter for "unknown" and complete the remaining assignments.

Windows: bash is not recognized

Use WSL (wsl --install, then open Ubuntu and follow the Linux path), or skip the script and run the PowerShell equivalents from the lesson's hands-on section, filling the worksheet manually.

Security notes

Security notes — Day 001 lab

  • What the scripts do: read system information (sysctl, lscpu, df, /proc, /etc/os-release) and print it. 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 will reinforce.
  • Privacy: a machine profile (CPU, RAM, OS version) is mildly identifying and reveals patch level. Sharing it in a class forum is normally fine; avoid posting profiles of employer-managed machines, and never share serial numbers or hardware UUIDs (this lab deliberately does not collect them).
  • 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.