Code of the Day
AdvancedShell mastery

Lab: Shell mastery

Hands-on quiz challenges covering parameter expansion edge cases, heredoc quoting rules, and signal handling patterns.

Lab · optionalBashAdvanced15 min
Recommended first
By the end of this lesson you will be able to:
  • Identify correct parameter expansion behaviour at the edges
  • Reason about heredoc quoting and indentation rules
  • Design reliable signal handling and cleanup patterns

This lab consolidates the Shell mastery module. Work through the questions to check your understanding, then run the hands-on challenges in a terminal to see the patterns in action.

Arrays and parameter expansion

  1. 1.
    file="report.tar.gz". What does ${file%%.*} produce?
  2. 2.
    VAR="" and you run: "${VAR:?must be set}". What happens?
  3. 3.
    path="/a/b/c/d". What does ${path#*/} produce?
  4. 4.
    ${var//old/new} replaces only the first occurrence of "old" in $var.

Heredocs and process substitution

  1. 1.
    You use <<-EOF. The heredoc body lines are indented with 4 spaces. What happens to the spaces?
  2. 2.
    diff <(sort a.txt) <(sort b.txt) — what does the <(sort ...) syntax do?
  3. 3.
    The herestring <<< word feeds the string to the command's stdin without launching a subshell for the receiving command.

Signal handling patterns

  1. 1.
    A script traps EXIT to delete a temp file. The user presses Ctrl-C (SIGINT). Does the trap fire?
  2. 2.
    You have background jobs stored in an array $pids. What is the correct EXIT trap to kill all of them reliably?

Do it yourself

Work through these hands-on challenges:

# 1. Parameter expansion: extract and transform a filename
file="My_Report_2024.CSV"
echo "Lowercase extension: ${file##*.}"   # should give CSV
ext="${file##*.}"
echo "${ext,,}"                           # csv — Bash 4+

# 2. Heredoc: write a script template without temp files
bash <<'SCRIPT'
  name="world"
  echo "Hello, $name"
  echo "This ran in a subshell via heredoc"
SCRIPT

# 3. Process substitution: find lines unique to file2
# (create test data)
printf "apple\nbanana\ncherry\n" > /tmp/list1.txt
printf "banana\ncherry\ndate\n" > /tmp/list2.txt
comm -13 <(sort /tmp/list1.txt) <(sort /tmp/list2.txt)
# Should print: date

# 4. Trap and background process cleanup
cleanup() { echo "Cleaning up pid $bgpid"; kill "$bgpid" 2>/dev/null; }
trap cleanup EXIT
sleep 60 &
bgpid=$!
echo "Background sleep pid: $bgpid"
echo "Exiting in 2 seconds..."
sleep 2
# trap fires here, kills the background sleep

Where to go next

Shell mastery is complete. The Automation module is next: scheduling with cron, Makefiles as task runners, writing robust CI shell scripts, and debugging techniques to find and fix the inevitable bugs.

Finished reading? Mark it complete to track your progress.

On this page