Special Variables
Bash provides several special variables that are automatically set and contain useful information about the script execution context. These variables give you access to command-line arguments, the script name, process IDs, exit statuses, and more. Understanding special variables is essential for writing scripts that accept arguments and handle errors properly!
Script Name: $0
The $0 variable contains the name of the script or command being executed. This is useful for error messages, help text, and logging.
Click Run to execute your code
#!/bin/bash
# Display script name
echo "This script is called: $0"
# Practical use: help message
if [ $# -eq 0 ]; then
echo "Usage: $0 <filename>"
exit 1
fi
Positional Parameters: $1, $2, ... $9
These variables contain the command-line arguments passed to your script. $1 is the first argument, $2 is the second, and so on.
| Variable | Contains | Example |
|---|---|---|
$1 |
First argument | ./script.sh hello โ $1 = "hello" |
$2 |
Second argument | ./script.sh hello world โ $2 = "world" |
$3 - $9 |
Third through ninth arguments | Access arguments by position |
${10}+ |
Arguments beyond 9th | Use braces: ${10}, ${11}, etc. |
#!/bin/bash
# Accessing arguments
echo "First argument: $1"
echo "Second argument: $2"
echo "Third argument: $3"
# Run with: ./script.sh apple banana cherry
${10}, ${11}, etc. Without braces, $10 would be interpreted as $1 followed by the literal "0"!
Number of Arguments: $#
The $# variable contains the total number of arguments passed to the script. This is essential for argument validation.
#!/bin/bash
echo "Number of arguments: $#"
# Validate argument count
if [ $# -lt 2 ]; then
echo "Error: Need at least 2 arguments"
echo "Usage: $0 <arg1> <arg2>"
exit 1
fi
echo "First arg: $1"
echo "Second arg: $2"
All Arguments: $@ and $*
Both $@ and $* represent all arguments, but they behave differently when quoted. Understanding this difference is crucial for writing robust scripts!
| Variable | Behavior | When to Use |
|---|---|---|
"$@" |
Each argument as separate word (preserves spaces) | Recommended - for passing arguments to other commands |
"$*" |
All arguments as single string (joined by IFS) | When you want all args as one string |
$@ (unquoted) |
Same as "$@" when used in loops |
In for loops: for arg in $@ |
$* (unquoted) |
Subject to word splitting (not recommended) | Avoid unquoted $* |
#!/bin/bash
# Difference between $@ and $*
# With arguments: ./script.sh "hello world" "foo bar"
echo "Using $@ (each argument separately):"
for arg in "$@"; do
echo " - '$arg'"
done
# Output:
# - 'hello world'
# - 'foo bar'
echo ""
echo "Using $* (all as one string):"
echo " '$*'"
# Output: 'hello world foo bar'
"$@" when passing arguments to other commands! This preserves spaces in arguments and handles special characters correctly. Unquoted $@ or $* can break with arguments containing spaces.
Process ID: $$
The $$ variable contains the Process ID (PID) of the current shell or script. This is useful for creating unique temporary files, logging, and process management.
#!/bin/bash
echo "This script's process ID: $$"
# Create unique temporary file
TEMP_FILE="/tmp/script_$$.tmp"
echo "Creating temp file: $TEMP_FILE"
touch "$TEMP_FILE"
# Cleanup on exit
trap "rm -f $TEMP_FILE" EXIT
Exit Status: $?
The $? variable contains the exit status of the last executed command. This is essential for error handling and conditional logic.
#!/bin/bash
# Exit status is 0 for success, non-zero for failure
# Run a command
ls /nonexistent 2>/dev/null
# Check exit status
if [ $? -eq 0 ]; then
echo "Command succeeded"
else
echo "Command failed with exit code: $?"
fi
# Check exit status immediately (before it changes)
ls /tmp
echo "Exit status: $?" # Must check immediately!
# After another command, $? changes
echo "test"
echo "Previous exit status lost: $?" # This shows echo's exit status (0)
| Exit Code | Meaning | Example |
|---|---|---|
0 |
Success | ls found files |
1 |
General error | grep found nothing |
2 |
Misuse of command | ls with invalid option |
126 |
Command not executable | Permission denied |
127 |
Command not found | Command doesn't exist |
130 |
Terminated by Ctrl+C | User interruption |
$? immediately after a command, before running any other command! Each new command overwrites $? with its own exit status.
Background Process ID: $!
The $! variable contains the Process ID of the last background job. This is useful for managing background processes.
#!/bin/bash
# Start a background job
sleep 10 &
BG_PID=$!
echo "Background process started with PID: $BG_PID"
# Wait for it to finish
wait $BG_PID
echo "Background process finished"
Common Mistakes
1. Using $* instead of "$@" when passing arguments
# Wrong - loses individual arguments
function process_args() {
for arg in "$*"; do
echo "$arg" # Only one iteration, all args joined!
done
}
# Correct - preserves individual arguments
function process_args() {
for arg in "$@"; do
echo "$arg" # One iteration per argument
done
}
2. Not checking $? immediately after command
# Wrong - $? might change
ls /tmp
echo "Something"
if [ $? -eq 0 ]; then # Checks echo's exit status, not ls!
echo "ls succeeded"
fi
# Correct - check immediately
ls /tmp
if [ $? -eq 0 ]; then # Checks ls exit status
echo "ls succeeded"
fi
# Even better - use if directly
if ls /tmp > /dev/null 2>&1; then
echo "ls succeeded"
fi
3. Accessing $10 without braces
# Wrong - interpreted as $1 + "0"
echo $10 # Prints value of $1 followed by literal "0"
# Correct - use braces
echo ${10} # Prints 10th argument
4. Assuming arguments exist without checking
# Wrong - no error handling
echo "First arg: $1"
echo "Second arg: $2"
# Correct - validate first
if [ $# -lt 2 ]; then
echo "Error: Need 2 arguments"
exit 1
fi
echo "First arg: $1"
echo "Second arg: $2"
Exercise: Create an Argument Processor
Task: Create a script that processes command-line arguments!
Requirements:
- Display the script name
- Display the total number of arguments
- Validate that at least 2 arguments are provided
- Display all arguments using
$@ - Display the first and second arguments
- Check if a command succeeds and display its exit status
Test with: bash script.sh apple banana cherry
Show Solution
#!/bin/bash
# Argument processor script
# Display script name
echo "Script name: $0"
echo ""
# Display argument count
echo "Number of arguments: $#"
echo ""
# Validate arguments
if [ $# -lt 2 ]; then
echo "Error: Need at least 2 arguments"
echo "Usage: $0 <arg1> <arg2> [arg3...]"
exit 1
fi
# Display all arguments
echo "All arguments ($@):"
for arg in "$@"; do
echo " - $arg"
done
echo ""
# Display first two arguments
echo "First argument: $1"
echo "Second argument: $2"
echo ""
# Check command exit status
ls /tmp > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "ls /tmp succeeded (exit status: $?)"
else
echo "ls /tmp failed (exit status: $?)"
fi
Summary
- $0: Script or command name
- $1-$9: First 9 command-line arguments
- ${10}+: Arguments beyond 9th (must use braces)
- $#: Total number of arguments
- "$@": All arguments as separate words (recommended)
- "$*": All arguments as single string
- $$: Current process ID (PID)
- $?: Exit status of last command (0 = success, non-zero = error)
- $!: Process ID of last background job
- Always use "$@" when passing arguments to preserve spaces
- Check $? immediately after commands, before running other commands
What's Next?
Excellent! You've mastered special variables for handling command-line arguments. Next, we'll explore Arrays - a powerful way to store and manipulate multiple values. Arrays let you work with lists of items, iterate through them, and perform bulk operations efficiently!
Enjoying these tutorials?