Bash exposes a set of special variables the shell maintains for you — exit
status, process IDs, positional parameters, and more. Misreading them, or
forgetting that $? is overwritten immediately, causes subtle scripting bugs.
This tool is a searchable reference of every special and automatic variable with
its meaning, scope, and a usage example.
How it works
These variables fall into a few families:
- Status & control —
$?(last exit code),$-(current shell flags),PIPESTATUS(per-command status of the last pipeline). - Process IDs —
$$(shell PID),$BASHPID(current process PID),$!(PID of the last background job),$PPID(parent PID). - Positional parameters —
$0(script name),$1…$9,${10},$#(count),$@and$*(all args),$_(last arg of previous command). - Shell internals —
$IFS(field separator),$RANDOM,$SECONDS,$LINENO,$FUNCNAME,$BASH_SOURCE.
Worked example
#!/usr/bin/env bash
process() {
grep -q "$1" "$2" # may succeed or fail
local status=$? # capture immediately
if (( status != 0 )); then
echo "not found (exit $status)" >&2
fi
}
for arg in "$@"; do # quoted "$@" keeps each arg intact
process "$arg" config.txt
done
false | true
echo "${PIPESTATUS[0]}" # 1 — the failing 'false', not the pipeline's 0
Notes
- Always quote
"$@"in loops and when forwarding arguments; unquoted$@re-splits on whitespace and breaks filenames with spaces. $?is clobbered by the next command — including the test in anif. Save it to a local variable the moment you need it.$$stays constant across subshells (it is the main shell’s PID); reach for$BASHPIDwhen you genuinely need the current subshell’s PID.$RANDOMreturns a value 0–32767 and is not cryptographically secure; use/dev/urandomfor security-sensitive randomness.