Special Variables
Bash provides several built-in special variables that give you access to script arguments, process information, and command status. These are essential for writing flexible and robust scripts.
Positional Parameters
These variables hold command-line arguments passed to your script:
| Variable | Description |
|---|---|
$0 | Script name (or shell name if interactive) |
$1 to $9 | First 9 arguments |
${10}, ${11} | Arguments 10 and beyond (braces required) |
$# | Number of arguments |
$@ | All arguments as separate words |
$* | All arguments as a single word |
#!/bin/bash
# save as show_args.sh
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo "Number of arguments: $#"
echo "All arguments: $@"
$@ vs $*
The difference becomes important with quoting:
# Given: ./script.sh "hello world" foo bar
# $@ preserves each argument separately
for arg in "$@"; do
echo "Arg: $arg"
done
# Output:
# Arg: hello world
# Arg: foo
# Arg: bar
# $* treats all as one string (separated by first char of IFS)
for arg in "$*"; do
echo "Arg: $arg"
done
# Output:
# Arg: hello world foo bar
Rule: Almost always use "$@" when iterating over arguments.
Exercise: Count Arguments
Work with positional parameters:
Process-Related Variables
| Variable | Description |
|---|---|
$$ | Current shell's process ID (PID) |
$! | PID of last background process |
$? | Exit status of last command |
$- | Current shell options |
echo "This script's PID: $$"
# Run something in background
sleep 10 &
echo "Background job PID: $!"
# Check last command status
ls /nonexistent
echo "Exit status: $?" # Non-zero (error)
ls /tmp
echo "Exit status: $?" # 0 (success)
The Exit Status $?
The exit status is crucial for error handling:
# 0 = success, non-zero = failure
grep "pattern" file.txt
if [ $? -eq 0 ]; then
echo "Pattern found"
else
echo "Pattern not found"
fi
# Common exit codes
# 0 - Success
# 1 - General error
# 2 - Misuse of command
# 126 - Permission denied
# 127 - Command not found
# 128+N - Killed by signal N
Exercise: Check Exit Status
Understand how exit status works:
Environment Variables
These are inherited from the parent process:
| Variable | Description |
|---|---|
$HOME | User's home directory |
$USER | Current username |
$PATH | Command search path |
$PWD | Current working directory |
$OLDPWD | Previous working directory |
$SHELL | Current shell path |
$HOSTNAME | System hostname |
$RANDOM | Random number (0-32767) |
$SECONDS | Seconds since shell started |
$LINENO | Current line number in script |
echo "Home: $HOME"
echo "User: $USER"
echo "Shell: $SHELL"
echo "Random: $RANDOM"
The $RANDOM Variable
Generate random numbers:
# Random number between 0 and 32767
echo $RANDOM
# Random number between 0 and 99
echo $((RANDOM % 100))
# Random number between 1 and 10
echo $((RANDOM % 10 + 1))
# Random number between MIN and MAX
MIN=5
MAX=15
echo $((RANDOM % (MAX - MIN + 1) + MIN))
The $SECONDS Variable
Track script execution time:
#!/bin/bash
SECONDS=0 # Reset timer
# ... do some work ...
sleep 2
echo "Script ran for $SECONDS seconds"
The $LINENO Variable
Useful for debugging:
#!/bin/bash
echo "This is line $LINENO"
echo "This is line $LINENO"
echo "This is line $LINENO"
# Output:
# This is line 2
# This is line 3
# This is line 4
IFS - Input Field Separator
Controls word splitting:
# Default IFS is space, tab, newline
echo "$IFS" | cat -A
# Custom IFS for parsing
DATA="apple,banana,cherry"
IFS=',' read -ra FRUITS <<< "$DATA"
for fruit in "${FRUITS[@]}"; do
echo "Fruit: $fruit"
done
Shifting Arguments
Use shift to move through arguments:
#!/bin/bash
# Process all arguments one at a time
while [ $# -gt 0 ]; do
echo "Processing: $1"
shift # Remove $1, shift others down
done
# After shift:
# $2 becomes $1
# $3 becomes $2
# $# decreases by 1
The set Command
Modify positional parameters:
# Set new positional parameters
set -- "arg1" "arg2" "arg3"
echo "$1" # arg1
echo "$2" # arg2
echo "$#" # 3
# Clear all parameters
set --
echo "$#" # 0
Exercise: Display Environment Info
Show multiple special variables:
Quick Reference
# Positional
$0 # Script name
$1-$9 # Arguments 1-9
${10} # Argument 10+
$# # Argument count
$@ # All args (separate)
$* # All args (single)
# Status
$? # Last exit status
$$ # Current PID
$! # Last background PID
# Environment
$HOME # Home directory
$USER # Username
$PWD # Current directory
$PATH # Command path
$RANDOM # Random number
$SECONDS # Seconds elapsed
$LINENO # Line number
Key Takeaways
$1,$2, etc. hold script arguments;$#is the count- Use
"$@"to iterate over arguments (preserves quoting) $?contains the exit status of the last command (0 = success)$$is the current process ID,$!is the last background job- Environment variables like
$HOME,$USER,$PWDare always available $RANDOMgenerates random numbers;$SECONDStracks timeshiftmoves through arguments, discarding the first one

