A Bash Special Variables Reference — $@ vs $*, Parameter Expansion, and 50+ More
"$@"and"$*"look identical but behave completely differently in a for loop.${var:-default}assigns a default without mutation,${var:=default}with mutation.${var%pattern}strips from the end,${var#pattern}from the start. 52 entries, bilingual explanations, examples you can copy-paste, all searchable.
Bash has dozens of magic variables and parameter expansion forms that experienced shell programmers use daily but that new users don't know exist. man bash is 40,000 words. A faster lookup tool exists, but none of them cover Japanese speakers, and most don't include the "why does this exist" context.
🔗 Live demo: https://sen.ltd/portfolio/bash-special-vars/
📦 GitHub: https://github.com/sen-ltd/bash-special-vars
Features:
- 52 entries in 6 categories
- Positional parameters ($0, $1-$9, $@, $*)
- Special parameters ($#, $?, $$, $!, $_, $-)
- Parameter expansion (${var:-default}, ${var%pattern}, etc.)
- Environment variables ($HOME, $PATH, $BASH_VERSION, etc.)
- Array syntax (${arr[@]}, ${#arr[@]})
- Process info ($LINENO, $FUNCNAME, $BASH_SOURCE)
- Bilingual Japanese / English descriptions
- Example + expected output per entry
- Dark / light theme
- Zero dependencies, 46 tests
The "$@" vs "$*" distinction
This is the most common Bash gotcha:
# "$@" expands to: "arg1" "arg2" "arg3" — separate quoted strings
for arg in "$@"; do echo "$arg"; done
# "$*" expands to: "arg1 arg2 arg3" — single concatenated string
for arg in "$*"; do echo "$arg"; done
The first form iterates over three arguments. The second form iterates once over a single string. When you want to forward arguments to another command unchanged, you want "$@". When you want to join arguments for logging, you want "$*".
Without quotes, $@ and $* behave identically — both split on IFS. The quotes matter.
Parameter expansion cheatsheet
13 expansion forms, each solving a different problem:
| Form | Behavior |
|---|---|
${var} |
Same as $var, but allows adjacent characters |
${var:-default} |
If var unset/empty, use default (no mutation) |
${var:=default} |
If var unset/empty, assign default |
${var:?error} |
If var unset/empty, print error and exit |
${var:+alt} |
If var set, use alt (opposite of :-) |
${var:offset:length} |
Substring extraction |
${#var} |
String length |
${var#pattern} |
Strip shortest match from start |
${var##pattern} |
Strip longest match from start |
${var%pattern} |
Strip shortest match from end |
${var%%pattern} |
Strip longest match from end |
${var/old/new} |
Replace first match |
${var//old/new} |
Replace all matches |
Pattern strippers (#, ##, %, %%) are how you parse filenames in pure Bash without sed:
file="/path/to/archive.tar.gz"
echo "${file##*/}" # archive.tar.gz (basename)
echo "${file%/*}" # /path/to (dirname)
echo "${file%.*}" # /path/to/archive.tar (strip last ext)
echo "${file%%.*}" # /path/to/archive (strip all ext)
Learning these four saves shelling out to basename / dirname / sed in every script.
$? vs $!
Two process-related variables that sound similar:
-
$?— Exit status of the most recently completed foreground command -
$!— PID of the most recently started background process
./long-running &
bg_pid=$!
./quick-check
echo "quick-check exit: $?"
wait $bg_pid
echo "long-running exit: $?"
The order matters: $? always refers to the last foreground command. Save it to a variable if you need to refer to it later.
Less-known but useful
-
$_— Last argument of the previous command.mkdir foo && cd $_saves typingcd foo. -
$LINENO— Current line number in the script. Useful in error messages. -
$BASH_SOURCE[0]— Path to the current script file, even when sourced. More reliable than$0. -
$RANDOM— A random 15-bit integer. Reseeds every read. -
$SECONDS— Seconds since shell started. Useful for simple benchmarks. -
$PS1— Primary prompt string. Changing it customizes your prompt. -
$IFS— Internal Field Separator. Changing toIFS=,lets you parse CSV withread -a.
Series
This is entry #67 in my 100+ public portfolio series.
- 📦 Repo: https://github.com/sen-ltd/bash-special-vars
- 🌐 Live: https://sen.ltd/portfolio/bash-special-vars/
- 🏢 Company: https://sen.ltd/

Top comments (0)