5.2. Variables & Expansion#

Variables are the fundamental way bash stores and manipulates data. Unlike compiled languages, bash variables are simple: they’re just named containers for strings. But that simplicity hides depth—understanding variable expansion is key to writing robust scripts.

5.2.1. Quick Reference#

Task

Syntax

Example

Create variable

var=value

name="Alice"

Use variable

$var or ${var}

echo $name

Quote in string

Double quotes

"Hello $name"

No expansion

Single quotes

'Cost: $5'

Export to children

export var

export API_KEY

Unset variable

unset var

unset temp

Test if set

${var:?error}

(Chapter 6)

Default value

${var:-default}

(Section 504)

5.2.2. Common Mistakes#

5.2.2.1. ❌ Mistake 1: Spaces Around =#

$ x = 5
bash: x: command not found

$ x=5  # ✓ Correct

5.2.2.2. ❌ Mistake 2: Forgetting Quotes#

$ filename="My File.txt"
$ cat $filename
cat: My: No such file or directory
cat: File.txt: No such file or directory

$ cat "$filename"  # ✓ Correct
My File.txt

5.2.2.3. ❌ Mistake 3: Unquoted in If Statements#

$ count="10"
$ if [ $count -gt 5 ]; then  # Works but risky
    echo "High"
fi

$ if [ "$count" -gt 5 ]; then  # ✓ Always quote
    echo "High"
fi

5.2.2.4. ❌ Mistake 4: Assuming Variables Persist#

$ (x=5)  # Subshell
$ echo $x
# (empty, x was in subshell only)

$ x=5  # Direct assignment
$ echo $x
5

5.2.3. Real-World Examples#

5.2.3.1. Script with Variables#

#!/bin/bash

# Configuration variables
log_file="/var/log/app.log"
backup_dir="/backups"
max_size=1000000  # 1MB

# Process the log
if [ -f "$log_file" ]; then
    size=$(stat -f%z "$log_file")
    
    if [ $size -gt $max_size ]; then
        cp "$log_file" "$backup_dir/app.log.$(date +%s)"
        > "$log_file"  # Clear it
        echo "Log rotated"
    fi
fi

5.2.3.2. Using Command Output in Variables#

# Capture command output
$ files=$(ls *.txt)
$ echo "Found files: $files"

# Use in loop
for f in $files; do
    echo "Processing $f"
done

# Capture with backticks (older syntax)
$ files=`ls *.txt`
# $(command) is preferred (nests better)

5.2.3.3. Variables in Paths#

# Build a dynamic path
project_name="myapp"
version="2.1"
build_dir="/opt/${project_name}/${version}"

echo "Installing to: $build_dir"
mkdir -p "$build_dir"

5.2.4. Unset Variables#

# Unset a variable
$ x="hello"
$ unset x
$ echo $x
# (empty, variable no longer exists)

# Check if variable is set
$ if [ -z "$x" ]; then
    echo "x is empty or not set"
fi

5.2.5. Variable Scope#

5.2.5.1. Function Scope#

# Global variable
count=10

# Function using global
increment_global() {
    ((count++))
}

increment_global
echo $count  # 11

# Function with local variable
my_function() {
    local temp="only in function"
    global="changed here"
}

my_function
echo $global      # "changed here"
echo $temp        # (empty, not in scope)

More on this in Chapter 8.

5.2.6. Environment vs Local Variables#

5.2.6.1. Local Variables (Current Shell)#

$ myvar="hello"
$ echo $myvar
hello

# Exit shell, variable is lost
$ exit

5.2.6.2. Environment Variables (Exported)#

# Create and export
$ export API_KEY="secret123"

# Or set and export together
$ export APP_MODE="production"

# Now child processes inherit it
$ bash -c 'echo $API_KEY'
secret123

# Check exported variables
$ env | grep API_KEY
API_KEY=secret123

5.2.6.3. When to Export#

  • Variables needed by child processes: export

  • Variables local to script: don’t export

#!/bin/bash

# Local variable (only this script)
filename="data.txt"

# Environment variable (for subcommands)
export JAVA_HOME="/usr/local/java"
export PATH="$PATH:./bin"

# Use local variable
process_file "$filename"

# Use environment variable in subprocess
java -version  # Uses $JAVA_HOME

5.2.7. Expansion: What Gets Replaced#

When bash encounters $something, it expands it. This is called variable expansion.

5.2.7.1. Types of Expansion#

# Simple variable expansion
$ name="Alice"
$ echo $name
Alice

# Parameter expansion (with braces, more explicit)
$ echo ${name}
Alice

# Needed when variable name is ambiguous
$ file="data"
$ echo ${file}txt    # ✓ RIGHT: ${file}txt → datatxt
$ echo $filetxt      # ✗ WRONG: looks for variable $filetxt

5.2.7.2. Expansion in Different Contexts#

# In double quotes
$ echo "Name: $name"
Name: Alice

# In single quotes (NO expansion)
$ echo 'Name: $name'
Name: $name

# Unquoted (word splitting happens)
$ echo $name
Alice

# In arithmetic
$ x=5
$ echo $((x + 1))
6

# In if statements
if [ "$count" -gt 10 ]; then
    echo "Many!"
fi

5.2.8. Special Variables#

Bash provides built-in variables with special meaning:

5.2.8.1. Common Built-in Variables#

Variable

Meaning

Example

$0

Script name

script.sh

$1, $2, etc.

Arguments

function $1 $2

$@

All arguments

for arg in "$@"

$#

Number of arguments

echo $#

$?

Last exit code

if [ $? -eq 0 ]

$$

Process ID

echo $$

$RANDOM

Random number 0-32767

$((RANDOM % 6))

$HOME

Home directory

/home/alice

$PWD

Current directory

/Users/alice/projects

$PATH

Executable search path

set of directories

$USER

Current username

alice

5.2.8.2. Examples#

# Current user
$ echo "Logged in as: $USER"
Logged in as: alice

# Home directory
$ echo "Home is: $HOME"
Home is: /home/alice

# Current directory
$ echo "Working in: $PWD"
Working in: /home/alice/scripts

# Random number
$ echo $RANDOM
24538

# Random between 1-10
$ echo $((RANDOM % 10 + 1))
7

5.2.9. Using Variables#

5.2.9.1. Basic Reference#

$ name="Alice"
$ echo $name
Alice

# Both work, but $var is more common
$ echo $name
$ echo ${name}
# In scripts, ${name} is safer (less ambiguous)

5.2.9.2. Variables in Strings#

Remember quoting from section 0502:

$ name="Alice"
$ greeting="Hello $name"
$ echo $greeting
Hello Alice

$ greeting='Hello $name'
$ echo $greeting
Hello $name
# Single quotes prevent expansion

5.2.9.3. Variables in Commands#

# Variable used as argument
$ filename="data.txt"
$ wc -l "$filename"
10 data.txt

# Variable in a pattern
$ pattern="error"
$ grep "$pattern" logfile.txt

# Variable as part of a filename
$ backup_dir="/backups"
$ cp datafile.txt "$backup_dir/datafile.txt.bak"

5.2.10. Creating Variables#

5.2.10.1. Basic Assignment#

# Create a variable and assign a value
$ name="Alice"
$ echo $name
Alice

# Note: NO spaces around the = sign
$ name = "Alice"  # ❌ WRONG: "name" is interpreted as a command
bash: name: command not found

$ name="Alice"    # ✓ RIGHT: Variable assignment

5.2.10.2. Variable Naming Rules#

# Valid variable names
$ count=5
$ _private=10
$ myVar="test"
$ MY_CONSTANT="PROD"

# Invalid (these won't work)
$ 1st="invalid"      # ❌ Can't start with number
$ my-var="test"      # ❌ Can't use hyphen
$ my var="test"      # ❌ Can't have spaces
$ my$var="test"      # ❌ Can't use special characters

5.2.10.3. Conventions#

  • Lowercase for local variables: filename, count

  • UPPERCASE for constants: API_KEY, MAX_RETRIES

  • Underscore prefix for private: _internal_var

  • Meaningful names: temp_file not tf