Table of Contents
- What Are Bash Variables?
- Types of Bash Variables
- Declaring and Using Variables
- Special Bash Variables
- Arrays in Bash
- Best Practices for Using Variables
- Practical Examples for Automation
- Conclusion
- References
What Are Bash Variables?
A Bash variable is a named storage location that holds data, such as text, numbers, or the output of a command. Variables allow you to store information temporarily and reuse it throughout a script, making your code more modular and easier to maintain.
For example, instead of hardcoding a file path like /home/user/docs directly in your script, you can store it in a variable (e.g., SOURCE_DIR). This makes the script easier to modify (you only update the variable once) and more readable.
Types of Bash Variables
Bash variables are broadly categorized into three types:
1. Local Variables
Local variables are scoped to a specific function or script and are not inherited by child processes. They are typically used for temporary storage within a script or function.
Example:
#!/bin/bash
# Local variable (only accessible in this script)
greeting="Hello, World!"
echo $greeting # Output: Hello, World!
2. Global Variables
Global variables are accessible throughout the entire script (and any functions within it) but are not exported to the environment. They persist across function calls but do not affect child processes.
Example:
#!/bin/bash
global_var="I'm global"
print_var() {
echo $global_var # Accessible inside the function
}
print_var # Output: I'm global
3. Environment Variables
Environment variables are global variables exported to the system environment, making them accessible to the current shell and all child processes (e.g., scripts, commands run from the shell). Common environment variables include PATH, HOME, and USER.
To create an environment variable, use the export command:
Example:
#!/bin/bash
# Export a variable to the environment
export APP_DIR="/opt/myapp"
# Child process (e.g., another script) can access $APP_DIR
./child_script.sh # If child_script.sh uses $APP_DIR, it will work
To view all environment variables, run printenv or env in the terminal.
Declaring and Using Variables
Basic Syntax
To declare a variable, use the format variable_name=value (no spaces around =):
name="Alice"
age=30
To access a variable’s value, prefix the name with $:
echo "Name: $name" # Output: Name: Alice
echo "Age: $age" # Output: Age: 30
For clarity (especially in complex expressions), wrap the variable name in curly braces ${}:
echo "Hello, ${name}!" # Output: Hello, Alice!
Assigning Command Output
Variables can store the output of commands using $(command) (preferred) or backticks `command`:
current_date=$(date +%Y-%m-%d) # Stores "2024-05-20" (example date)
echo "Today is $current_date"
# Using backticks (older syntax)
current_time=`date +%H:%M:%S`
echo "Current time: $current_time"
Overwriting Variables
Variables can be updated by reassigning them:
count=5
echo $count # Output: 5
count=10
echo $count # Output: 10
Special Bash Variables
Bash provides predefined “special variables” that store metadata about the shell, scripts, and processes. These are critical for writing dynamic and interactive scripts.
| Variable | Description | Example |
|---|---|---|
$0 | Name of the current script | echo "Script name: $0" → Script name: ./my_script.sh |
$1, $2, ..., $9 | Positional parameters (arguments passed to the script) | ./script.sh arg1 arg2 → $1=arg1, $2=arg2 |
${10}, ${11}, ... | Positional parameters beyond 9 (requires curly braces) | ./script.sh a b c ... j → ${10}=j |
$# | Number of positional parameters | ./script.sh a b c → echo $# → 3 |
$* | All positional parameters as a single string | ./script.sh a b c → echo "$*" → a b c |
$@ | All positional parameters as separate strings (preferred over $*) | ./script.sh a b c → for arg in "$@"; do echo $arg; done → a, b, c |
$? | Exit status of the last command (0 = success, non-zero = failure) | ls non_existent_file; echo $? → 2 (failure) |
$$ | PID (Process ID) of the current shell/script | echo "My PID: $$" → My PID: 12345 |
$! | PID of the last background process | sleep 10 & echo "Background PID: $!" → Background PID: 67890 |
Example: Using Positional Parameters
#!/bin/bash
# script.sh
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo "Total arguments: $#"
# Loop through all arguments with $@
echo "All arguments:"
for arg in "$@"; do
echo "- $arg"
done
Output:
./script.sh apple banana cherry
Script name: ./script.sh
First argument: apple
Second argument: banana
Total arguments: 3
All arguments:
- apple
- banana
- cherry
Example: Exit Status ($?)
ls /valid/directory # Success
echo "Exit status: $?" # Output: Exit status: 0
ls /invalid/directory # Failure
echo "Exit status: $?" # Output: Exit status: 2 (varies by error)
Arrays in Bash
Arrays allow you to store multiple values in a single variable, making them ideal for lists (e.g., filenames, IP addresses).
Declaring Arrays
# Indexed array (most common)
fruits=("apple" "banana" "cherry" "date")
# Alternative syntax
colors=("red" "green" "blue")
Accessing Elements
- Access by index (starts at 0):
${array[index]} - All elements:
${array[@]}or${array[*]} - Length:
${#array[@]}
Example:
fruits=("apple" "banana" "cherry" "date")
echo "First fruit: ${fruits[0]}" # Output: apple
echo "All fruits: ${fruits[@]}" # Output: apple banana cherry date
echo "Number of fruits: ${#fruits[@]}" # Output: 4
Modifying Arrays
fruits=("apple" "banana" "cherry")
# Update an element
fruits[1]="blueberry" # Now: ("apple" "blueberry" "cherry")
# Add an element
fruits+=("date") # Now: ("apple" "blueberry" "cherry" "date")
# Delete an element
unset fruits[2] # Now: ("apple" "blueberry" "date") (note: index 2 is removed)
Looping Through Arrays
fruits=("apple" "banana" "cherry")
for fruit in "${fruits[@]}"; do
echo "I like $fruit"
done
Output:
I like apple
I like banana
I like cherry
Best Practices for Using Variables
To write robust and maintainable scripts, follow these best practices:
1. Naming Conventions
- Use uppercase for environment variables (e.g.,
PATH,BACKUP_DIR). - Use lowercase for local/global variables (e.g.,
file_count,user_input). - Avoid reserved names (e.g.,
PATH,HOME,IFS).
2. Quote Variables to Handle Spaces
Always quote variables with "$variable" to preserve spaces and special characters:
Bad:
file="my document.txt"
rm $file # Tries to delete "my" and "document.txt" (fails)
Good:
file="my document.txt"
rm "$file" # Correctly deletes "my document.txt"
3. Avoid Undefined Variables
Use set -u at the top of your script to exit if an undefined variable is used (prevents silent failures):
#!/bin/bash
set -u # Exit on undefined variable
echo $undefined_var # Script exits with error: "undefined_var: unbound variable"
4. Use readonly for Constant Values
Mark variables that shouldn’t be modified as readonly:
readonly MAX_RETRIES=3
MAX_RETRIES=4 # Error: "MAX_RETRIES: readonly variable"
5. Comment Complex Variables
Explain the purpose of non-trivial variables for readability:
# Path to log file (auto-created if missing)
LOG_FILE="/var/log/backup_script_$(date +%Y%m%d).log"
Practical Examples for Automation
Let’s apply what we’ve learned with a real-world automation script: a backup tool that uses variables to make the script flexible and reusable.
Example: Backup Script with Variables
#!/bin/bash
set -u # Exit on undefined variables
# Configuration variables (modify these as needed)
SOURCE_DIR="/home/user/documents" # What to back up
DEST_DIR="/mnt/external_drive/backups" # Where to store backups
TIMESTAMP=$(date +%Y%m%d_%H%M%S) # Unique timestamp for the backup file
BACKUP_FILE="$DEST_DIR/backup_$TIMESTAMP.tar.gz" # Full path to backup
# Check if source directory exists
if [ ! -d "$SOURCE_DIR" ]; then
echo "Error: Source directory $SOURCE_DIR does not exist."
exit 1
fi
# Create destination directory if it doesn't exist
mkdir -p "$DEST_DIR"
# Perform backup
echo "Starting backup of $SOURCE_DIR to $BACKUP_FILE..."
tar -czf "$BACKUP_FILE" "$SOURCE_DIR"
# Check if backup succeeded
if [ $? -eq 0 ]; then
echo "Backup completed successfully! File: $BACKUP_FILE"
else
echo "Error: Backup failed."
exit 1
fi
Key Variables in Action:
SOURCE_DIRandDEST_DIRmake the script easy to reconfigure.TIMESTAMPensures each backup has a unique filename (avoids overwrites).BACKUP_FILEcombinesDEST_DIR,TIMESTAMP, and a filename template.$?checks if thetarcommand succeeded.
Conclusion
Bash variables are the building blocks of dynamic, efficient Linux automation. By mastering variable declaration, special variables, arrays, and best practices, you can write scripts that adapt to changing needs, handle edge cases, and are easy to maintain.
Whether you’re automating backups, processing logs, or managing server tasks, variables empower you to create flexible tools that save time and reduce errors. Start small, experiment with the examples above, and gradually incorporate these techniques into your workflow—your future self (and colleagues) will thank you!
References
- GNU Bash Manual
- Bash Hackers Wiki: Variables
- ShellCheck (tool to lint bash scripts for best practices)
- TLDP Bash Guide (Beginner-friendly Bash tutorial)