Complete Guide to Bash Variables

Introduction to Bash Variables

Variables in Bash are fundamental containers for storing and manipulating data. They allow you to store values, reference them throughout your scripts, and perform operations on them. Understanding Bash variables is crucial for writing effective shell scripts.

Key Concepts

  • No Data Types: All variables are stored as strings
  • Case-Sensitive: $VAR and $var are different
  • Scope: Variables can be global or local
  • Special Variables: Positional parameters and system variables
  • Expansion: Variables are expanded with $ prefix

1. Basic Variable Declaration

Simple Variable Assignment

#!/bin/bash
# Basic assignment (no spaces around =)
name="John Doe"
age=25
city="New York"
# Accessing variables
echo "$name is $age years old and lives in $city"
# Output: John Doe is 25 years old and lives in New York
# Variables without $ when assigning, with $ when accessing
greeting="Hello"
echo $greeting World
echo "${greeting}, World!"  # Curly braces for clarity

Variable Naming Rules

#!/bin/bash
# Valid variable names
name="John"
NAME="John"          # Different from 'name'
_name="John"         # Starting with underscore
name123="John"       # Numbers allowed after first character
long_variable_name="John"  # Underscores for readability
# Invalid variable names
# 123name="John"     # Cannot start with number
# my-name="John"     # Hyphen not allowed
# my name="John"     # Space not allowed
# $name="John"       # $ not allowed in assignment
# Best practices
# Use lowercase for local variables
# Use UPPERCASE for environment variables and constants
local_var="value"
readonly MAX_COUNT=100
export GLOBAL_CONFIG="/etc/app/config"

2. Variable Types and Usage

String Variables

#!/bin/bash
# String assignment
name="John Doe"
empty_string=""
space_string=" "  # String with a space
# String concatenation
first="John"
last="Doe"
full="$first $last"
echo "$full"  # John Doe
# Quotes matter
var1=Hello World    # Error: World treated as command
var2="Hello World"  # Correct
var3='Hello World'  # Correct (literal)
# Single vs Double quotes
name="John"
echo "Hello $name"   # Hello John (variable expanded)
echo 'Hello $name'   # Hello $name (literal)
# Escaping quotes
message="He said: \"Hello\""
echo "$message"
# Multi-line strings
multiline="Line 1
Line 2
Line 3"
echo "$multiline"

Numeric Variables (All strings, but can be used in arithmetic)

#!/bin/bash
# Numbers are stored as strings
count="10"
echo "$count"
# Arithmetic expansion
sum=$((5 + 3))
echo "Sum: $sum"  # Sum: 8
# Different arithmetic operations
a=10
b=3
echo "Addition: $((a + b))"        # 13
echo "Subtraction: $((a - b))"     # 7
echo "Multiplication: $((a * b))"  # 30
echo "Division: $((a / b))"        # 3 (integer division)
echo "Modulus: $((a % b))"         # 1
echo "Power: $((a ** 2))"          # 100
# Using let for arithmetic
let "result = a + b"
echo "Result: $result"  # Result: 13
# Increment/decrement
counter=0
((counter++))
echo "$counter"  # 1
((counter--))
echo "$counter"  # 0
((counter+=5))
echo "$counter"  # 5

Arrays

#!/bin/bash
# Indexed arrays
fruits=("apple" "banana" "orange")
numbers=(1 2 3 4 5)
mixed=("hello" 42 "world" 3.14)
# Accessing array elements
echo "${fruits[0]}"  # apple
echo "${fruits[1]}"  # banana
echo "${fruits[@]}"  # all elements
echo "${#fruits[@]}" # array length
# Adding elements
fruits[3]="grape"
fruits+=("kiwi" "mango")
# Iterating over array
for fruit in "${fruits[@]}"; do
echo "Fruit: $fruit"
done
# Associative arrays (Bash 4+)
declare -A capitals
capitals["USA"]="Washington"
capitals["France"]="Paris"
capitals["Japan"]="Tokyo"
echo "${capitals["France"]}"  # Paris
echo "${!capitals[@]}"        # all keys
echo "${capitals[@]}"         # all values
# Iterate over associative array
for country in "${!capitals[@]}"; do
echo "$country: ${capitals[$country]}"
done

3. Special Variables

Positional Parameters

#!/bin/bash
# script.sh
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo "Third argument: $3"
echo "All arguments: $@"
echo "Number of arguments: $#"
echo "All arguments (as single string): $*"
# Shift through arguments
echo "Processing arguments:"
while [ $# -gt 0 ]; do
echo "Argument: $1"
shift
done
# Example usage
# ./script.sh arg1 arg2 arg3

Special Shell Variables

#!/bin/bash
# Process ID
echo "Current shell PID: $$"
echo "Last background process PID: $!"
# Exit status
echo "Last command exit status: $?"
# Shell options
echo "Shell options: $-"
# Previous working directory
cd /tmp
cd ~
echo "Previous directory: $OLDPWD"
# Current working directory
echo "Current directory: $PWD"
# Random number
echo "Random number: $RANDOM"
echo "Another random: $RANDOM"
# Line number
echo "Current line number: $LINENO"

Environment Variables

#!/bin/bash
# Common environment variables
echo "Home directory: $HOME"
echo "User: $USER"
echo "Username: $LOGNAME"
echo "Shell: $SHELL"
echo "Path: $PATH"
echo "Terminal: $TERM"
echo "Language: $LANG"
echo "Hostname: $HOSTNAME"
echo "Display: $DISPLAY"
# Setting environment variables
export MY_APP_CONFIG="/etc/myapp/config"
export DATABASE_URL="postgresql://localhost/mydb"
# Environment for a single command
PATH="/custom/bin:$PATH" command_name
# Listing all environment variables
env
printenv
declare -p  # Show all variables

4. Variable Operations

String Operations

#!/bin/bash
# String length
str="Hello World"
echo "Length: ${#str}"  # 11
# Substring extraction
echo "${str:6}"         # World (from position 6)
echo "${str:6:3}"       # Wor (3 chars from position 6)
echo "${str: -5}"       # World (last 5 chars)
echo "${str: -5:2}"     # Wo (2 chars from 5 from end)
# Pattern removal
filename="document.txt"
echo "${filename%.txt}"      # document (remove suffix)
echo "${filename%.*}"        # document (remove shortest suffix)
echo "${filename%%.*}"       # document (remove longest suffix)
path="/home/user/file.txt"
echo "${path#*/}"            # home/user/file.txt (remove shortest prefix)
echo "${path##*/}"           # file.txt (remove longest prefix)
# Search and replace
text="Hello Hello World"
echo "${text/Hello/Hi}"      # Hi Hello World (first match)
echo "${text//Hello/Hi}"     # Hi Hi World (all matches)
echo "${text/#Hello/Hi}"     # Hi Hello World (match at start)
echo "${text/%World/All}"    # Hello Hello All (match at end)
# Default values
unset var
echo "${var:-default}"       # default (if unset or empty)
echo "${var-default}"        # default (only if unset)
echo "${var:=default}"       # assign default and return
echo "$var"                  # default (now assigned)
# Error if unset
echo "${var:?Error message}" # prints error if unset or empty

Case Modification (Bash 4+)

#!/bin/bash
# Uppercase/lowercase
name="john DOE"
echo "${name^}"      # John DOE (first letter uppercase)
echo "${name^^}"     # JOHN DOE (all uppercase)
echo "${name,}"      # john DOE (first letter lowercase)
echo "${name,,}"     # john doe (all lowercase)
# Case transformation with patterns
text="hello-world"
echo "${text^}"                     # Hello-world
echo "${text^^}"                    # HELLO-WORLD
echo "${text^^[a-z]}"               # HELLO-WORLD
echo "${text^^[a]}"                  # hello-world (only a)

5. Variable Scope

Local vs Global Variables

#!/bin/bash
# Global variable
global_var="I'm global"
function test_scope() {
# Local variable
local local_var="I'm local"
echo "Inside function: $global_var"
echo "Inside function: $local_var"
# Modify global
global_var="Modified global"
# Create new global inside function
new_global="Created in function"
}
test_scope
echo "Outside: $global_var"        # Modified global
echo "Outside: $local_var"          # Empty (not accessible)
echo "Outside: $new_global"         # Created in function
# Function with local variables only
function calculate() {
local result=$(( $1 + $2 ))
echo "$result"
}
sum=$(calculate 5 3)
echo "Sum: $sum"

Exporting Variables

#!/bin/bash
# Export variable to child processes
export CONFIG_FILE="/etc/myapp/config"
export DEBUG=true
# Export after assignment
DATABASE_URL="postgresql://localhost/db"
export DATABASE_URL
# Export multiple variables
export VAR1="value1" VAR2="value2" VAR3="value3"
# Child script (child.sh)
cat > child.sh << 'EOF'
#!/bin/bash
echo "Config file: $CONFIG_FILE"
echo "Debug mode: $DEBUG"
EOF
chmod +x child.sh
./child.sh
# Unset variable
unset DATABASE_URL
unset VAR1 VAR2 VAR3

6. Advanced Variable Techniques

Indirect Expansion

#!/bin/bash
# Variable indirection
fruit_apple="Apple is red"
fruit_banana="Banana is yellow"
fruit="apple"
echo "${fruit_$fruit}"  # Error
echo "${fruit_apple}"   # Apple is red
# Using indirection
chosen="apple"
ref="fruit_$chosen"
echo "${!ref}"          # Apple is red (indirect expansion)
# Practical example
config_user="admin"
config_pass="secret"
config_host="localhost"
for setting in user pass host; do
ref="config_$setting"
echo "Setting $setting: ${!ref}"
done

Variable Attributes

#!/bin/bash
# Readonly variables
readonly PI=3.14159
PI=3.14  # Error: cannot modify readonly
# Integer attribute
declare -i number
number=10
number="5"      # Works (string converted to integer)
number="hello"  # Becomes 0
echo "$number"
# Array attributes
declare -a indexed_array
declare -A associative_array
# Lowercase/Uppercase attributes
declare -l lowercase="HELLO"  # Automatically lowercase
echo "$lowercase"  # hello
declare -u uppercase="hello"  # Automatically uppercase
echo "$uppercase"  # HELLO
# Read from file
declare -a lines
mapfile -t lines < file.txt
echo "${lines[0]}"

Dynamic Variable Names

#!/bin/bash
# Creating dynamic variable names
for i in {1..5}; do
declare "var_$i=$i"
done
echo "$var_1"  # 1
echo "$var_5"  # 5
# Using eval (be careful!)
name="value"
eval "$name='Hello World'"
echo "$value"  # Hello World
# Better: using declare
for i in {1..3}; do
declare "fruit_$i=$(echo "fruit$i")"
done
# List variables with pattern
echo "${!fruit_@}"  # fruit_1 fruit_2 fruit_3
echo "${!fruit_*}"  # fruit_1 fruit_2 fruit_3

7. Variable Expansion and Quoting

Quote Types

#!/bin/bash
# Double quotes (allow expansion)
name="John"
echo "Hello $name"      # Hello John
echo "Hello \$name"     # Hello $name (escaped)
# Single quotes (literal)
echo 'Hello $name'      # Hello $name
echo 'Hello "World"'    # Hello "World"
# No quotes (word splitting, globbing)
echo Hello   World      # Hello World (multiple spaces collapsed)
echo *                  # Lists files in current directory
# ANSI-C quoting ($'...')
echo $'Hello\nWorld'    # Newline interpretation
echo $'Tab\there'       # Tab character
echo $'Bell\a'          # Bell character
echo $'Quote: \''       # Single quote

Word Splitting

#!/bin/bash
# IFS (Internal Field Separator)
data="apple:banana:orange"
# Default IFS (space, tab, newline)
for item in $data; do
echo "$item"  # Splits by spaces (none here) - whole string
done
# Change IFS
IFS=":"
for item in $data; do
echo "$item"  # Splits by colon: apple, banana, orange
done
# Reset IFS
unset IFS
# Preserve spaces with IFS
IFS=$'\n'  # Newline only
# Word splitting examples
list="one two three"
set -- $list  # Split into positional parameters
echo "$1"  # one
echo "$2"  # two
echo "$3"  # three
# Prevent word splitting
list="one two three"
set -- "$list"  # No splitting
echo "$1"  # one two three

8. Command Substitution

Basic Command Substitution

#!/bin/bash
# Old style (backticks)
files=`ls`
echo "Files: $files"
# Modern style ($())
files=$(ls)
echo "Files: $files"
# Nesting command substitution
output=$(echo "Date: $(date)")
echo "$output"
# Complex examples
current_date=$(date +%Y-%m-%d)
echo "Today: $current_date"
lines=$(wc -l < file.txt)
echo "Lines: $lines"
# Using in arithmetic
count=$(grep -c "pattern" file.txt)
echo "Matches: $((count * 2))"
# Multi-line output
files_list=$(ls -la)
echo "$files_list"  # Quotes preserve newlines

Process Substitution

#!/bin/bash
# Process substitution (Bash 4+)
diff <(ls dir1) <(ls dir2)
# Compare files
while read line; do
echo "Processed: $line"
done < <(grep "pattern" file.txt)
# Multiple process substitutions
paste <(cut -f1 file1) <(cut -f2 file2)
# Complex example
while IFS= read -r line1 && IFS= read -r line2 <&3; do
echo "Line1: $line1, Line2: $line2"
done < <(command1) 3< <(command2)

9. Variable Attributes and Declare

Using declare/typeset

#!/bin/bash
# Declare variable with attributes
declare -r READONLY_VAR="Cannot change"
declare -i INTEGER=10
declare -a ARRAY=(1 2 3)
declare -A ASSOC=([key]=value)
declare -x EXPORTED_VAR="Visible to child processes"
declare -l LOWERCASE="HELLO"
declare -u UPPERCASE="hello"
# List variables
declare -p          # Show all variables with attributes
declare -p PATH     # Show PATH variable details
# Function-local variables
function test() {
declare -i local_int=5
echo "$local_int"
}
# Read-only array
declare -ra COLORS=("red" "green" "blue")
# COLORS[0]="yellow"  # Error: readonly
# Export array (not directly possible)
# Workaround using string
declare -ax MY_ARRAY=(1 2 3)  # Still won't export

Variable Attributes Examples

#!/bin/bash
# Integer arithmetic with declare -i
declare -i count
count=10
count+=5           # Addition, not concatenation
echo "$count"      # 15
count="2 * 3"
echo "$count"      # 6
# Lowercase/Uppercase with assignment
declare -l name="JOHN DOE"
echo "$name"       # john doe
name="JANE SMITH"
echo "$name"       # jane smith
declare -u code="abc123"
echo "$code"       # ABC123
# Trace function calls
declare -t TRACE_VAR="track this"
set -o functrace
# Array attributes
declare -a numbers
numbers[5]=10
echo "${#numbers[@]}"  # 1 (sparse array)
echo "${!numbers[@]}"  # 5 (indexes)

10. Practical Examples

Configuration File Parser

#!/bin/bash
# Simple config parser
parse_config() {
local config_file="$1"
while IFS='=' read -r key value; do
# Skip comments and empty lines
[[ "$key" =~ ^#.*$ || -z "$key" ]] && continue
# Trim whitespace
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
# Remove quotes if present
value="${value%\"}"
value="${value#\"}"
value="${value%\'}"
value="${value#\'}"
# Export as variable
export "$key=$value"
done < "$config_file"
}
# Example config file
cat > app.conf << 'EOF'
# Application configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DEBUG=true
MAX_CONNECTIONS=100
EOF
# Parse and use
parse_config app.conf
echo "Database: $DB_NAME on $DB_HOST:$DB_PORT"
echo "Debug mode: $DEBUG"

Safe Variable Handling

#!/bin/bash
# Safe variable access with defaults
get_env() {
local var_name="$1"
local default="${2:-}"
if [ -n "${!var_name}" ]; then
echo "${!var_name}"
else
echo "$default"
fi
}
# Validate variable is set
require_var() {
local var_name="$1"
local message="${2:-Required variable $var_name is not set}"
if [ -z "${!var_name}" ]; then
echo "ERROR: $message" >&2
exit 1
fi
}
# Use defaults
DB_HOST=$(get_env "DB_HOST" "localhost")
DB_PORT=$(get_env "DB_PORT" "5432")
# Require critical variables
require_var "API_KEY" "API key must be set"
# Safe array handling
safe_array_get() {
local array_name="$1"
local index="$2"
local default="${3:-}"
eval "value=\"\${${array_name}[$index]:-}\""
if [ -n "$value" ]; then
echo "$value"
else
echo "$default"
fi
}

Variable Scope Manager

#!/bin/bash
# Save and restore variable states
save_vars() {
local save_file="${1:-/tmp/vars_save}"
declare -p | grep -v "^declare -[aA]" > "$save_file"
}
restore_vars() {
local save_file="${1:-/tmp/vars_save}"
if [ -f "$save_file" ]; then
source "$save_file"
rm "$save_file"
fi
}
# Temporary variable changes
with_vars() {
local vars_file="/tmp/vars_$$"
save_vars "$vars_file"
# Set temporary variables
eval "$1"
# Run command
eval "${@:2}"
# Restore
restore_vars "$vars_file"
}
# Usage
with_vars "PATH=/custom/bin:\$PATH; DEBUG=1" "my_command --verbose"

Environment Manager

#!/bin/bash
# Environment setup/teardown
setup_environment() {
local env_file="$1"
# Save current environment
declare -p > "/tmp/env_before_$$"
# Load new environment
while IFS= read -r line; do
[[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
export "$line"
done < "$env_file"
}
teardown_environment() {
# Restore previous environment
while IFS= read -r line; do
if [[ "$line" =~ ^declare\ -x\ ([^=]+)= ]]; then
var="${BASH_REMATCH[1]}"
unset "$var"
fi
done < "/tmp/env_before_$$"
# Reload saved variables
source "/tmp/env_before_$$"
rm "/tmp/env_before_$$"
}
# Environment profiles
profile_dev() {
export DB_HOST="localhost"
export DB_NAME="dev_db"
export DEBUG=1
}
profile_prod() {
export DB_HOST="prod.db.example.com"
export DB_NAME="prod_db"
export DEBUG=0
}
# Switch profile
use_profile() {
local profile="$1"
"profile_$profile"
}

11. Error Handling with Variables

Variable Validation

#!/bin/bash
# Validate variable types
validate_integer() {
local var_name="$1"
local value="${!var_name}"
if [[ ! "$value" =~ ^-?[0-9]+$ ]]; then
echo "Error: $var_name must be an integer" >&2
return 1
fi
}
validate_positive() {
local var_name="$1"
local value="${!var_name}"
if [[ ! "$value" =~ ^[0-9]+$ ]] || [ "$value" -le 0 ]; then
echo "Error: $var_name must be positive integer" >&2
return 1
fi
}
validate_email() {
local var_name="$1"
local value="${!var_name}"
if [[ ! "$value" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Error: $var_name must be valid email" >&2
return 1
fi
}
validate_ip() {
local var_name="$1"
local value="${!var_name}"
if [[ ! "$value" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
echo "Error: $var_name must be valid IP" >&2
return 1
fi
# Validate each octet
IFS='.' read -r a b c d <<< "$value"
if [ "$a" -gt 255 ] || [ "$b" -gt 255 ] || [ "$c" -gt 255 ] || [ "$d" -gt 255 ]; then
echo "Error: $var_name contains invalid octet" >&2
return 1
fi
}

Defensive Programming

#!/bin/bash
# Set strict mode
set -euo pipefail
# Check required variables
required_vars=("DB_HOST" "DB_USER" "DB_PASS")
for var in "${required_vars[@]}"; do
if [ -z "${!var:-}" ]; then
echo "Error: $var is not set" >&2
exit 1
fi
done
# Use default values safely
: "${MAX_RETRIES:=3}"
: "${TIMEOUT:=30}"
# Prevent unset variable errors
set -u
echo "$UNDEFINED_VAR"  # This will error
# Safer alternative
echo "${UNDEFINED_VAR:-}"  # Empty string if unset
# Check if variable is set
if [ -n "${SOME_VAR+set}" ]; then
echo "SOME_VAR is set"
else
echo "SOME_VAR is not set"
fi

12. Performance and Best Practices

Variable Performance Tips

#!/bin/bash
# Use local variables in functions (faster)
function slow() {
for i in {1..1000}; do
global_var=$i  # Global variable (slower)
done
}
function fast() {
local local_var
for i in {1..1000}; do
local_var=$i   # Local variable (faster)
done
}
# Avoid unnecessary command substitution
# Slow
for i in $(seq 1 1000); do
# ...
done
# Fast
for ((i=1; i<=1000; i++)); do
# ...
done
# Use built-in operations instead of external commands
# Slow
len=$(echo -n "$string" | wc -c)
# Fast
len=${#string}
# Use arrays instead of string parsing
# Better
files=("$@")
for file in "${files[@]}"; do
echo "$file"
done
# Avoid eval when possible
# Dangerous
eval "var_$i='value'"
# Safer
declare "var_$i=value"

Best Practices

#!/bin/bash
# 1. Always quote variables
file="my file.txt"
cat "$file"      # Good
cat $file        # Bad (breaks with spaces)
# 2. Use descriptive names
user_input="data"           # Good
ui="data"                   # Bad (too short)
path_to_config_file="/etc/app/config"  # Good
p="/etc/app/config"         # Bad (not descriptive)
# 3. Use readonly for constants
readonly MAX_CONNECTIONS=100
readonly PI=3.14159
# 4. Initialize variables
local var=""                # Good
local var                   # Bad (may inherit previous value)
# 5. Use lowercase for local variables
local user_name="John"      # Good
local USER_NAME="John"      # Bad (looks like environment)
# 6. Use uppercase for exported variables
export APP_HOME="/opt/myapp"  # Good
export app_home="/opt/myapp"  # Bad (convention)
# 7. Check variables before use
if [ -n "${filename:-}" ]; then
process "$filename"
fi
# 8. Use default values
timeout=${TIMEOUT:-30}
debug=${DEBUG:-false}
# 9. Clean up sensitive variables
secret_key="supersecret"
process_data "$secret_key"
unset secret_key
# 10. Use arrays for lists
# Instead of: fruits="apple banana orange"
fruits=("apple" "banana" "orange")
for fruit in "${fruits[@]}"; do
echo "$fruit"
done

13. Common Pitfalls and Solutions

Variable Pitfalls

#!/bin/bash
# Pitfall 1: Spaces in assignments
# Wrong
name = "John"     # Error: name command not found
# Correct
name="John"
# Pitfall 2: Forgetting $ when reading
count=5
echo count        # prints "count", not 5
echo "$count"     # prints 5
# Pitfall 3: Word splitting
files="file1 file2 file3"
for file in $files; do  # Works but fragile
echo "$file"
done
# Better
files=("file1" "file2" "file3")
for file in "${files[@]}"; do
echo "$file"
done
# Pitfall 4: Globbing with unquoted variables
pattern="*"
echo $pattern      # Lists files in directory
echo "$pattern"    # Prints *
# Pitfall 5: Environment inheritance
export VAR="value"
(export VAR="child"; echo "$VAR")  # Prints "child"
echo "$VAR"                         # Prints "value" (unchanged)
# Pitfall 6: Array vs string
array=(1 2 3)
echo "$array"       # Prints "1" (only first element)
echo "${array[@]}"  # Prints "1 2 3"
# Pitfall 7: Unset variables in strict mode
set -u
echo "$UNDEFINED"   # Error
# Safer
echo "${UNDEFINED:-}"
# Pitfall 8: Exporting arrays
export myarray=(1 2 3)  # Doesn't work
# Workaround: export as string
export myarray="1 2 3"
# Pitfall 9: Variable scope in pipelines
count=0
echo -e "1\n2\n3" | while read line; do
((count++))
done
echo "$count"  # Still 0 (subshell issue)
# Fix with process substitution
count=0
while read line; do
((count++))
done < <(echo -e "1\n2\n3")
echo "$count"  # 3
# Pitfall 10: Using echo with flags
var="-n"
echo "$var"      # Prints nothing (interpreted as echo flag)
printf "%s\n" "$var"  # Safe alternative

14. Command Summary and Cheat Sheet

Variable Operations Quick Reference

# Assignment
name="value"
readonly constant="value"
export global="value"
declare -i integer=5
declare -a array=(1 2 3)
declare -A dict=([key]="value")
# Access
$name
${name}
${#name}                    # Length
${name:offset:length}       # Substring
${name#pattern}             # Remove shortest prefix
${name##pattern}            # Remove longest prefix
${name%pattern}             # Remove shortest suffix
${name%%pattern}            # Remove longest suffix
${name/pattern/replacement} # Replace first
${name//pattern/replacement} # Replace all
${name^}                     # First character uppercase
${name^^}                    # All uppercase
${name,}                     # First character lowercase
${name,,}                    # All lowercase
# Default values
${var:-default}              # Use default if unset/empty
${var-default}               # Use default if unset
${var:=default}              # Assign default if unset/empty
${var:=default}              # Assign default if unset
${var:?error}                # Error if unset/empty
${var?error}                 # Error if unset
# Indirect expansion
${!var}                       # Indirect reference
# Array operations
${array[@]}                   # All elements
${!array[@]}                  # Array indices
${#array[@]}                  # Array length
array+=("new")                 # Append
unset array[2]                 # Remove element
# Special variables
$0                            # Script name
$1, $2...                     # Positional parameters
$@                            # All arguments
$*                            # All arguments (as string)
$#                            # Number of arguments
$?                            # Exit status
$$                            # Process ID
$!                            # Last background PID
$-                            # Shell options

Common Patterns

# Safe variable access
: "${VAR:=default}"           # Set default if unset
: "${VAR:?Required}"          # Error if unset
# Variable testing
[ -n "$VAR" ]                  # Not empty
[ -z "$VAR" ]                  # Empty
[ "${VAR+set}" = "set" ]       # Is set (even if empty)
# Variable transformation
lower=$(echo "$VAR" | tr '[:upper:]' '[:lower:]')
upper=$(echo "$VAR" | tr '[:lower:]' '[:upper:]')
trimmed=$(echo "$VAR" | xargs)
# Loops with variables
for var in "${list[@]}"; do
echo "$var"
done
while IFS= read -r line; do
echo "$line"
done < file.txt

Conclusion

Bash variables are essential for effective shell scripting:

Key Takeaways

  1. No types - all variables are strings, but can be used numerically with arithmetic
  2. Case-sensitive - naming conventions matter
  3. Scope - understand local vs global vs environment
  4. Expansion - ${} provides powerful manipulation
  5. Arrays - indexed and associative for complex data
  6. Special variables - positional parameters and system info

Best Practices Summary

PracticeExample
Quote variables"$var"
Use local in functionslocal var
Use uppercase for constantsreadonly MAX=100
Use lowercase for localslocal count
Use arrays for listsfiles=("$@")
Check variables before use[ -n "$var" ]
Set defaults: "${var:=default}"
Clean sensitive dataunset password

Common Commands Summary

# Variable operations
declare      # Set attributes
export       # Make available to children
local        # Function-local
readonly     # Make read-only
unset        # Remove variable
set          # Show all variables/env
# Information
env          # Show environment
printenv     # Print environment
echo         # Display values
printf       # Formatted output

Mastering Bash variables is fundamental to writing robust, maintainable shell scripts. They provide the foundation for data manipulation, configuration management, and program flow control in the Unix/Linux environment.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper