100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Linux & Shell Scripting
45 minbeginner

Getting Started Practice — Explore a Live System

What You'll Build

In this exercise you will build `cricket_inventory.sh` — a production-grade system inventory script that an operations engineer can run on any unfamiliar Linux server to produce a structured, timestamped report about the server's identity, resource state, and application health. This is exactly the kind of script that DevOps and SRE teams maintain for onboarding new servers and performing pre-deployment checks.

The script will identify the Linux distribution and kernel version, report CPU and memory utilisation, enumerate mounted filesystems with threshold-based warnings, list listening network ports, and check for CricketPulse application artifacts in their FHS-correct locations. Every section uses the commands and concepts from Lessons 01–03 in a realistic operational context.

By the end of this exercise you will have practised filesystem navigation, environment variable inspection, process checking, and threshold logic — not as isolated commands but as components of a coherent diagnostic tool that solves a real problem that every DevOps team faces.

Analogy🏏Cricket
🏏 Think of it like cricket: This script is like the pre-match ground inspection conducted by the match referee, pitch curator, and captains before a Test match begins. Before Rohit Sharma and the opposition captain walk out for the toss, the curator has measured pitch moisture, taken grass length readings, and documented the surface condition — creating a baseline against which any afternoon deterioration can be measured.Just as this structured inspection prevents surprises and creates a documented record, the inventory script creates a documented baseline for a server against which future anomalies can be compared. Just as a ground inspection without a checklist might miss a drainage issue that affects the afternoon session, a server assessment without a structured script might miss a nearly-full disk that causes a midnight deployment failure.The insight is that the value of a structured inspection is not just the current findings but the reproducible method — the same script run tomorrow highlights exactly what changed.

Prerequisites

  • Completion of Lessons 01–03: understanding of Linux purpose, shell types, FHS directory structure, and navigation commands.
  • A running Linux system — Ubuntu 20.04 or later recommended — either a local VM, WSL2, or a cloud instance (AWS/GCP/Azure free tier works).
  • Basic ability to open a terminal and run simple commands like `ls`, `pwd`, and `echo`.
  • A text editor accessible from the terminal — `nano` is sufficient; `vim` or VS Code remote also work.
  • Sudo access on the target system for commands requiring elevated privileges such as network port inspection.

Setup & Project Structure

This exercise requires only a text editor and a Linux shell — no additional software needs to be installed. You will create a single script file called `cricket_inventory.sh` in a dedicated exercise directory, make it executable, and run it directly. The script is built incrementally across four steps — each step adds one report section and introduces the specific commands used to gather that information.

Analogy🏏Cricket
🏏 Think of it like cricket: building `cricket_inventory.sh` incrementally across four steps is like a batter building an innings session by session rather than swinging for six off the first ball. Just as you only need a bat and a net to start practising — no fancy equipment — this exercise needs only a text editor and a shell, nothing installed. Just as a batter grooves one shot at a time, the cover drive before the pull, each step adds exactly one report section and introduces only the commands needed to gather that piece of information. Just as marking your guard and taking centre sets a repeatable stance, creating a dedicated exercise directory and making the file executable gives you a clean, runnable base to return to. And just as a solid start makes the big total possible, getting the script structure right first means the later sections drop in without collapse. The payoff: incremental practice builds a working system-inventory script the same disciplined way a batter builds a match-winning score.

After each step, run the partial script and verify its output before moving to the next step. This incremental approach builds confidence that each section works correctly before adding complexity — the same practice used when writing production scripts, where you validate each component before composing them.

bash
# Create the project directory and script file
mkdir -p ~/devops_exercises/linux_module1
cd ~/devops_exercises/linux_module1

# Create the script with correct permissions from the start
touch cricket_inventory.sh
chmod 755 cricket_inventory.sh

# Verify executable bit is set
ls -la cricket_inventory.sh
# Expected: -rwxr-xr-x 1 youruser yourgroup 0 [date] cricket_inventory.sh

# Open in your editor
nano cricket_inventory.sh

Step 1 — Foundation: Identity and Distribution

Step 1 establishes the script's structure and collects the most fundamental information: who the server is and what it runs. Every subsequent diagnostic decision depends on knowing the distribution — which package manager is available, which init system manages services, and which paths to expect for configuration and logs.

This step introduces the script's defensive header (`set -euo pipefail`), the output formatting functions that will be reused throughout, and the commands for reading system identity from `/etc/os-release` and `uname`. Understanding `uname -r` (kernel version) matters because kernel bugs and security patches are version-specific — documenting it is the first thing a support engineer asks for during a kernel-level issue.

Analogy🏏Cricket
🏏 Think of it like cricket: Identifying the system is like reading the match conditions card at the start of a series. Before the first ball of a Border-Gavaskar Trophy series, both teams receive the official playing conditions document specifying ball type, over limits, and DRS reviews. Every tactical decision flows from this baseline document.Just as a captain who skips reading the playing conditions might field an incorrect XI or misuse DRS reviews, a DevOps engineer who skips distribution identification might run APT commands on a CentOS server. Just as the conditions document is the foundation for all match strategy, system identity is the foundation for all operational decisions.The insight is that identity verification is not a formality — it is the gate that determines which of your knowledge applies.
bash
#!/bin/bash
# cricket_inventory.sh — Step 1: System Identity
set -euo pipefail

TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
REPORT_FILE="/tmp/inventory_$(hostname)_$(date '+%Y%m%d_%H%M%S').txt"

# Reusable formatting functions
section() { echo; echo "════════════════════════"; echo "  $1"; echo "════════════════════════"; }
info()    { echo "  ✓ $1"; }
warn()    { echo "  ⚠ WARNING: $1"; }

{
  echo "CricketPulse Server Inventory — $TIMESTAMP"
  echo "Hostname: $(hostname -f)"

  section "SYSTEM IDENTITY"

  if [ -f /etc/os-release ]; then
    . /etc/os-release           # Source to get variables
    info "Distribution: ${PRETTY_NAME}"
    info "Version ID:   ${VERSION_ID:-unknown}"
  else
    warn "/etc/os-release not found — cannot identify distribution"
  fi

  info "Kernel:       $(uname -r)"
  info "Architecture: $(uname -m)"
  info "Boot time:    $(uptime -s 2>/dev/null || echo 'unavailable')"
  info "Uptime:       $(uptime -p 2>/dev/null || uptime | awk '{print $3, $4}' | tr -d ',')"

} | tee "$REPORT_FILE"

echo "Report: $REPORT_FILE"

Step 2 — Core Logic: Resources and Filesystem

Step 2 extends the script to collect resource utilisation and filesystem state. CPU and memory information are drawn from `/proc/cpuinfo` and `/proc/meminfo` — virtual files created by the kernel that expose system state as readable text. Nearly every metric that Prometheus node_exporter exposes ultimately comes from reading files in `/proc`.

Filesystem usage is collected with `df -h`, filtered to real filesystems, with a threshold check that marks any filesystem above 80% utilisation as a warning. This threshold logic is the same pattern that production monitoring systems like Grafana alerting implement — by building it into the inventory script, you practise thinking in operational thresholds rather than raw values.

Analogy🏏Cricket
🏏 Think of it like cricket: Resource monitoring is like a physio's pre-match fitness assessment. Before every match, India's physio conducts quick assessments — checking Bumrah's bowling shoulder load, Rohit's hamstring, Kohli's back stiffness. Each has a threshold: green means full duty, yellow means restricted, red means unavailable.Just as the threshold-based assessment immediately communicates player readiness without requiring the captain to interpret raw medical data, the 80% disk threshold communicates filesystem status without requiring interpretation of raw `df` numbers. Just as ignoring yellow flags leads to mid-match injuries, ignoring 80% disk warnings leads to mid-deployment failures.The insight is that threshold-based alerting transforms raw metrics into actionable information — the pattern used by every production monitoring system from Nagios to Datadog.
bash
# Step 2 additions — append inside the report block

  section "CPU & MEMORY"

  CPU_COUNT=$(grep -c '^processor' /proc/cpuinfo)
  CPU_MODEL=$(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)
  info "CPU cores: $CPU_COUNT"
  info "CPU model: $CPU_MODEL"

  MEM_TOTAL_KB=$(grep '^MemTotal:'     /proc/meminfo | awk '{print $2}')
  MEM_AVAIL_KB=$(grep '^MemAvailable:' /proc/meminfo | awk '{print $2}')
  MEM_TOTAL_GB=$(echo "scale=1; $MEM_TOTAL_KB/1048576" | bc)
  MEM_USED_PCT=$(echo "scale=0; (($MEM_TOTAL_KB - $MEM_AVAIL_KB) * 100) / $MEM_TOTAL_KB" | bc)
  info "Total RAM: ${MEM_TOTAL_GB}GB"
  if [ "$MEM_USED_PCT" -gt 85 ]; then
    warn "Memory usage ${MEM_USED_PCT}% — HIGH"
  else
    info "Memory usage: ${MEM_USED_PCT}%"
  fi

  section "FILESYSTEM USAGE"

  while IFS= read -r line; do
    USE_PCT=$(echo "$line" | awk '{print $5}' | tr -d '%')
    if [ "${USE_PCT:-0}" -gt 80 ]; then
      warn "$line   ← ABOVE 80%"
    else
      info "$line"
    fi
  done < <(df -h --output=source,size,used,avail,pcent,target | \
           grep -v -E '^(tmpfs|devtmpfs|udev|Filesystem)')

  section "INODE USAGE"
  df -i --output=source,ipcent,target | grep -v -E '^(tmpfs|devtmpfs|Filesystem)' | \
  while read -r line; do
    PCT=$(echo "$line" | awk '{print $2}' | tr -d '%-')
    if [ "${PCT:-0}" -gt 80 ] 2>/dev/null; then warn "$line   ← HIGH INODES"
    else info "$line"; fi
  done
Lesson 4 of 40
0% complete