Capstone: Build a Log Summary Tool

Published by Programming Line in Bash Shell Scripting. Last updated .

This capstone combines strict mode, arguments, validation, safe file reading, arrays, arithmetic, functions, and formatted output. The result is a small log-summary tool that counts severity levels without losing whitespace or relying on unsafe parsing.

This lesson develops Capstone: Build a Log Summary Tool from its underlying shell behavior through practical, runnable examples. The goal is not merely to memorize punctuation, but to understand what Bash expands, what it executes, and how to keep data boundaries intact.

How Capstone: Build a Log Summary Tool Works

The script treats each line as LEVEL: message, validates the file before processing, stores counters in an associative array, and prints a deterministic report. Each operation has one responsibility, which makes the script straightforward to extend and test.

Bash processes source in stages: it parses the command, performs the relevant expansions, applies redirections, and finally runs a builtin, function, or external program. Quoting affects the expansion stage, while control structures react to exit statuses. Keeping these stages separate in your mental model makes debugging much faster.

Syntax

./log-summary.sh application.log
# Output: counts grouped by INFO, WARNING, and ERROR

Whitespace and quoting are part of the language. Do not copy a compact example and then remove quotes or spaces casually: those characters often determine argument boundaries or separate reserved words. Use bash -n script.sh to check syntax without executing the script.

Worked Examples

Example 1: Core behavior

declare -A counts=([INFO]=0 [WARNING]=0 [ERROR]=0)
while IFS=: read -r level message; do
  [[ -v 'counts[$level]' ]] && ((counts[$level] += 1))
done <<'LOGS'
INFO: started
ERROR: connection failed
WARNING: retrying
ERROR: timeout
LOGS
for level in INFO WARNING ERROR; do
  printf '%-7s %d\n' "$level" "${counts[$level]}"
done

Output:

INFO    1
WARNING 1
ERROR   2

The first example keeps every expansion explicit and quotes values at the point where Bash builds the command’s arguments. Trace it one line at a time: assignments update shell state, expansions produce values, and printf receives a format plus distinct arguments.

Example 2: Practical composition

summarize() {
  local total=0
  local value
  for value in "$@"; do
    ((total += value))
  done
  printf 'Total events: %d\n' "$total"
}

summarize 1 1 2

Output:

Total events: 4

The second example composes the feature with another shell capability. Its output is deterministic, so you can paste the script into a temporary file, run it, and compare every line. If your result differs, enable a trace locally and inspect the expanded arguments rather than guessing.

Execution Step by Step

  1. Bash reads enough input to form a complete command or compound command.
  2. Parameter, command, and arithmetic expansions are performed where the syntax requests them.
  3. Quoting determines whether expanded text stays together as one argument.
  4. Redirections are connected before the selected command runs.
  5. The command returns an exit status, which a conditional, loop, or following command may use.

This sequence also explains why printing a variable can look correct even when passing it unquoted is unsafe: the destructive splitting happens while Bash constructs arguments, not while the value is stored.

Common Mistakes

  • Assuming every line has a known level without validating the key.
  • Mixing report output with diagnostics, which makes the tool difficult to pipe into another command.

Another common mistake is testing only the happy path. Shell programs interact with files, permissions, processes, and user-controlled strings. Always try an empty value, a value containing spaces, and a failing command. Those tests expose most quoting and error-handling defects early.

Best Practices

  • Keep parsing, counting, and presentation separate.
  • Test empty files, unknown levels, missing files, and whitespace-containing messages.
  • Add options only after the core behavior is reliable.

For production automation, start scripts with a clear interpreter line, document inputs and outputs, keep functions small, and run ShellCheck. Strict settings can help, but explicit validation and purposeful error messages remain necessary.

Practice Exercises

  • Recreate the first Capstone: Build a Log Summary Tool example without copying it, then change one input containing a space.
  • Add one validation failure that prints a useful message to standard error and returns a non-zero status.
  • Wrap the central behavior in a function and call it twice with different arguments.

Summary

  • Capstone: Build a Log Summary Tool is easiest to use correctly when you track parsing, expansion, execution, and exit status separately.
  • Quoted expansions preserve data boundaries and should be the default.
  • Deterministic examples, syntax checks, and failure-path tests turn shell snippets into reliable automation.