Bash Special Parameters: The Hidden Power Tools
Bash provides several special parameters that are automatically set by the shell. These parameters can only be referenced - never assigned to - and they provide powerful functionality for script writing.
The Complete List of Special Parameters
| Parameter | Description |
|---|---|
$0 | Name of the script or shell |
$# | Number of positional parameters |
$* | All parameters as a single string |
$@ | All parameters as separate words |
$? | Exit status of last command |
$$ | Process ID of current shell |
$! | Process ID of last background command |
$- | Current shell options |
$_ | Last argument of previous command |
Deep Dive into $* vs $@
These two parameters are the most confusing for beginners, but understanding their difference is crucial.
Basic Behavior (Unquoted)
./script.sh one "two three" fourBoth $* and $@ behave identically when unquoted:
$*→one two three four$@→one two three four
The Critical Difference (Quoted)
This is where the magic happens:
"$*" = All parameters as one single string
# Arguments: one "two three" four# "$*" → "one two three four""$@" = Each parameter as separate words
# Arguments: one "two three" four# "$@" → "one" "two three" "four"Practical Demonstration
The Word Splitting Problem
Let’s see what happens with a script that creates files:
#!/bin/bashtouch $*Running: ./test.sh "file one.txt" "file two.txt"
Result: Creates 4 files instead of 2:
fileone.txtfiletwo.txt
Why? Because $* without quotes causes word splitting.
The Solution: Quoted $@
#!/bin/bashtouch "$@"Running: ./test.sh "file one.txt" "file two.txt"
Result: Creates 2 files correctly:
file one.txtfile two.txt
Real-World Examples
Example 1: Processing All Arguments
#!/bin/bashecho "Processing $# files..."
for file in "$@"; do echo "Processing: $file" # Do something with each file wc -l "$file"doneWhy $@? Each filename might contain spaces.
Example 2: Building a Command String
#!/bin/bash# When you need all arguments as one stringtar -czf backup.tar.gz "$*"Why $*? When you want to treat all arguments as a single entity.
The $_ Parameter
This is often overlooked but incredibly useful:
#!/bin/bash# Shows the last argument of the previous command
ls -la /etc/passwdecho "Last argument was: $_" # Output: /etc/passwd
cd /var/logecho "Last argument was: $_" # Output: /var/logThe $? Parameter: Exit Status
Understanding Exit Codes
#!/bin/bash# Check if a file exists
if [ -f "$1" ]; then echo "File exists"else echo "File does not exist"fi
echo "Exit status: $?" # 0 for success, non-zero for failurePractical Usage
#!/bin/bash# Validate and use exit status
grep "error" logfile.txtif [ $? -eq 0 ]; then echo "Errors found!"else echo "No errors"fiThe $$ and $! Parameters
Process IDs
#!/bin/bashecho "My PID: $$"
# Start a background processsleep 60 &echo "Background PID: $!"
# Kill the background processkill $!Advanced Usage Patterns
Pattern 1: Safe Argument Iteration
#!/bin/bash# Always use "$@" for safe iteration
for arg in "$@"; do echo "Argument: $arg"donePattern 2: Shift and Process
#!/bin/bash# Process arguments one by one
while [ $# -gt 0 ]; do case "$1" in --file) FILE="$2" shift 2 ;; --verbose) VERBOSE=1 shift ;; *) echo "Unknown: $1" shift ;; esacdonePattern 3: Default Values
#!/bin/bash# Provide defaults for missing arguments
FILENAME="${1:-default.txt}"LINES="${2:-10}"
echo "Processing $FILENAME for $LINES lines"Common Mistakes to Avoid
❌ Wrong: Unquoted $@ in loops
for file in $@; do # Breaks on spaces process "$file"done✅ Correct: Quoted $@
for file in "$@"; do process "$file"done❌ Wrong: Using $* when you need individual args
echo "$*" # "one two three" - one string✅ Correct: Using $@ for individual args
for arg in "$@"; do # "one", "two", "three" - separate echo "$arg"doneSummary: When to Use What
| Scenario | Use | Why |
|---|---|---|
| Looping through arguments | "$@" | Preserves spaces in each argument |
| Counting arguments | $# | Simple count |
| Getting all as one string | "$*" | Treats all as single entity |
| Checking success/failure | $? | Exit status |
| Getting script name | $0 | Script invocation name |
| Process management | $$, $! | PIDs for scripting |
Best Practices
- Always quote
$@in loops and arrays - Use
$*only when you explicitly want one string - Check
$?after critical commands - Use
$#to validate argument count - Document your script with
$0in error messages
What’s Next?
Now that you’ve mastered special parameters, you’re ready to explore shell expansions - a powerful feature that lets you generate lists and patterns dynamically!