Skip to content

Portal | Level: L0: Entry | Topics: Bash / Shell Scripting | Domain: Linux

Bash - Skill Check

Mental model (bottom-up)

Bash takes text and does parsing + expansions + word splitting + globbing, then execs programs. Most Bash bugs are: unquoted expansions, IFS/whitespace, or subshell scope.

Visual stack

[Script text     ]  what you typed
|
[Parser          ]  builds commands/words/redirects
|
[Expansions      ]  vars, command subst, arithmetic, globs
|
[Word splitting  ]  IFS splits unquoted expansions into multiple args
|
[Exec            ]  runs builtins or forks external commands

Glossary

  • word splitting - turning one string into multiple args on whitespace/IFS
  • globbing - expanding * ? [] patterns into filenames
  • subshell - child shell; variable changes don't persist to parent
  • pipeline - cmd1 | cmd2 (stdout of left becomes stdin of right)
  • here-doc - multiline input redirected into a command (<<EOF)
  • trap - run cleanup code on signals/exit
  • exit code - 0 success; nonzero means failure

Expansion order (why quoting matters)

brace -> tilde -> parameter/command/arithmetic -> word splitting -> globbing

Common failure modes

  • for f in $(find ...) explodes on whitespace/newlines.
  • Missing pipefail hides errors in pipelines.
  • Using echo for data (it lies); prefer printf.

Roadmap core (10, easy -> hard)

  • Single quotes vs double quotes?
  • '...' no expansion; "..." expands variables/escapes.
  • "$@" vs "$*"?
  • "$@" preserves args; "$*" joins into one string.
  • What does set -euo pipefail do?
  • Exit on error/unset var; fail pipelines if any command fails.
  • Safely loop over filenames with spaces?
  • while IFS= read -r -d '' f; do ...; done < <(find ... -print0)
  • stdout+stderr to file?
  • cmd >out 2>&1 (or cmd &>out)
  • stderr only to file?
  • cmd 2>err
  • Strip suffix .log from var?
  • ${x%.log}
  • Default if unset/empty?
  • ${x:-default}
  • Trap cleanup on exit?
  • trap 'rm -f "$tmp"' EXIT
  • Why pipelines hide failures + fix?
  • Exit code is last command; use pipefail or inspect ${PIPESTATUS[@]}.

Quoting & expansions (easy -> hard)

  • What's word-splitting?
  • Unquoted expansion splits on IFS; surprise extra args.
  • Why prefer "${var}" over $var?
  • Prevents globbing/splitting; preserves empty values.
  • ${var:=default} vs ${var:-default}?
  • := assigns if unset/empty; :- substitutes only.
  • What does ${var%/*} do?
  • Strip shortest suffix matching /* (dirname-ish).
  • What is globbing and how to disable?
  • * ? [] pattern expansion; set -f disables.
  • [[ ... ]] vs [ ... ]?
  • [[ avoids word-splitting/globbing in many cases and supports regex.

Control flow & data (easy -> hard)

  • Why case beats if chains?
  • Cleaner matching; less quoting pain.
  • Arrays: append and iterate safely?
  • a+=("$x"); for x in "${a[@]}"; do ...; done
  • Why read -r?
  • Prevents backslash escapes from being interpreted.
  • What does IFS= in read do?
  • Prevents trimming leading/trailing whitespace.
  • Process substitution < <(...) vs pipe |?
  • Keeps loop in current shell (often) and preserves variables.
  • When to avoid for f in $(...)?
  • Breaks on whitespace/newlines; use find -print0 + read -d ''.

Defensive Bash (easy -> hard)

  • Why set -u can bite you?
  • Unset vars abort; guard with ${var-} or defaults.
  • How to fail with a useful message?
  • die(){ echo "ERR: $*" >&2; exit 1; }
  • How to validate args fast?
  • Check count, types, file exists/readable/writable; [[ -f ... ]].
  • Why use mktemp?
  • Avoid predictable temp names; prevent races/attacks.
  • How to prevent partial writes?
  • Write to temp, mv atomic replace.
  • Why shellcheck matters?
  • Catches quoting bugs and common footguns.

Text processing boundaries (easy -> hard)

  • When to use grep/sed/awk vs pure Bash?
  • Use tools for streaming transforms; keep Bash for orchestration.
  • Why LC_ALL=C sometimes?
  • Deterministic byte-wise ordering and faster collation.
  • How to handle NUL-delimited streams?
  • -print0 + xargs -0 / read -d ''.
  • What is "UUOC" and why care?
  • "Useless use of cat"; avoid extra processes in hot paths.
  • What does "avoid subshell" mean?
  • Some pipelines spawn subshell; variables won't persist.

Performance patterns (easy -> hard)

  • What kills Bash performance?
  • Per-line forks; heavy subshells; $(...) in tight loops.
  • Batch external calls how?
  • Use xargs -0 -n or aggregate into fewer invocations.
  • Why prefer builtins (printf) over echo?
  • Predictable behavior; fewer portability surprises.
  • When do you switch to Python?
  • Complex parsing, data structures, concurrency, tests.

Visual guides

BAD:  cmd=$(cat file)         # UUOC + memory blowup
GOOD: while IFS= read -r line; do ...; done < file

Sources

  • GNU Bash Reference Manual; POSIX shell docs.
  • https://www.gnu.org/software/bash/manual/

Wiki Navigation