Web Analytics

Special Variables

Beginner ~20 min read

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.

Output
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
Accessing Arguments Beyond $9: For the 10th argument and beyond, you must use braces: ${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'
Important: Always use "$@" 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
Pro Tip: Check $? 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!