Shell_expansion
Chapter 27: Shell Expansion in Bash
Section titled “Chapter 27: Shell Expansion in Bash”Overview
Section titled “Overview”Shell expansion is the process by which the shell interprets special characters and replaces them with their values before executing a command. Understanding expansion is crucial for writing effective bash scripts and understanding how the shell processes your commands.
Types of Expansion
Section titled “Types of Expansion”┌────────────────────────────────────────────────────────────────┐│ Shell Expansion Types │├────────────────────────────────────────────────────────────────┤│ ││ 1. Brace Expansion {a,b,c} → a b c ││ 2. Tilde Expansion ~ → /home/user ││ 3. Parameter Expansion $VAR → value ││ 4. Command Substitution $(cmd) → output ││ 5. Arithmetic Expansion $((expr)) → result ││ 6. Word Splitting splits on IFS ││ 7. Pathname Expansion *.txt → file1.txt file2.txt ││ 8. Quote Removal "text" → text ││ ││ Order of Operations: ││ ────────────────── ││ 1. Brace Expansion ││ 2. Tilde Expansion ││ 3. Parameter, Command, Arithmetic Expansion ││ 4. Word Splitting ││ 5. Pathname Expansion ││ 6. Quote Removal ││ │└────────────────────────────────────────────────────────────────┘Brace Expansion
Section titled “Brace Expansion”Basic Braces
Section titled “Basic Braces”# Generate sequencesecho {1..5}# 1 2 3 4 5
echo {01..05}# 01 02 03 04 05
echo {a..e}# a b c d e
echo {A..E}# A B C D ECombinations
Section titled “Combinations”# File extensionsecho file.{txt,log,json}# file.txt file.log file.json
# Directory structuremkdir -p project/{src,tests,docs}
# Multiple levelscp file.{log,bak}# file.log file.bak
# Nested bracesecho {{A,B},{C,D}}# A B C DPadding with Zeros
Section titled “Padding with Zeros”# With leading zerosecho {01..10}# 01 02 03 04 05 06 07 08 09 10
# Without zerosecho {1..10}# 1 2 3 4 5 6 7 8 9 10Tilde Expansion
Section titled “Tilde Expansion”Basic Tilde
Section titled “Basic Tilde”# Home directoryecho ~# Specific user's homeecho ~root# /root
echo ~guest# /home/guestTilde in Paths
Section titled “Tilde in Paths”# Current user's homels ~/documents
# Relative to homels ~- # Previous directory ($OLDPWD)echo ~+ # Current directory ($PWD)
# In variableexport PROJECT_DIR=~/projects/myappParameter Expansion
Section titled “Parameter Expansion”Basic Variables
Section titled “Basic Variables”# Simple expansionecho $HOMEecho $USERecho $PATH
# Curly braces (recommended)echo ${HOME}echo ${USER}Advanced Parameter Expansion
Section titled “Advanced Parameter Expansion”# Default values${parameter:-word} # Use default if unset or null${parameter:=word} # Assign default if unset or null${parameter:+word} # Use alternate if set${parameter:?word} # Error if unset or null${parameter:?} # Print error if unset
# Examplesecho ${HOME:-/tmp} # Use /tmp if HOME unsetecho ${HOME:=/home/default} # Assign if unsetecho ${HOME:+/alternate} # Use alternate if set
# Length${#parameter} # Length of valueecho ${#HOME}String Operations
Section titled “String Operations”# Substring removal${parameter#pattern} # Remove shortest match from beginning${parameter##pattern} # Remove longest match from beginning${parameter%pattern} # Remove shortest match from end${parameter%%pattern} # Remove longest match from end
# Examplespath="/home/user/documents/file.txt"echo ${path##*/} # file.txt (remove path)echo ${path%.txt} # /home/user/documents/file (remove extension)
# Substring${parameter:offset} # From offset to end${parameter:offset:length} # Slice
text="Hello World"echo ${text:0:5} # Helloecho ${text:6:5} # WorldPattern Replacement
Section titled “Pattern Replacement”# Replace first match${parameter/pattern/string}
# Replace all matches${parameter//pattern/string}
# Examplestext="hello world hello"echo ${text/hello/bye} # bye world helloecho ${text//hello/bye} # bye world bye
# Prefix/suffix${parameter/#pattern/string} # Replace if at beginning${parameter/%pattern/string} # Replace if at end
file="test.txt"echo ${file/#test/backup} # backup.txtecho ${file/%txt/log} # test.logCommand Substitution
Section titled “Command Substitution”Basic Command Substitution
Section titled “Basic Command Substitution”# Modern syntax (recommended)$(command)
# Legacy syntax`command`
# Examplescurrent_date=$(date)echo $current_date
files=$(ls -1)echo $files
# Using output in variablecount=$(ls -1 *.txt | wc -l)echo "Text files: $count"Nested Command Substitution
Section titled “Nested Command Substitution”# Nested commandsouter=$(inner=$(echo hello); echo $inner)echo $outer
# Practical nestedfiles=$(ls $(pwd))Arithmetic Expansion
Section titled “Arithmetic Expansion”Basic Math
Section titled “Basic Math”# Using $(( ))result=$(( 5 + 3 ))echo $result # 8
# Various operationsecho $(( 10 - 3 )) # 7echo $(( 5 * 3 )) # 15echo $(( 10 / 3 )) # 3 (integer)echo $(( 10 % 3 )) # 1
# Powerecho $(( 2 ** 10 )) # 1024Variables in Math
Section titled “Variables in Math”x=10y=3
echo $(( x + y )) # 13echo $(( x - y )) # 7echo $(( x * y )) # 30echo $(( x / y )) # 3echo $(( x % y )) # 1Increment/Decrement
Section titled “Increment/Decrement”x=5
# Pre-incrementecho $(( ++x )) # 6echo $x # 6
# Post-incrementecho $(( x++ )) # 6echo $x # 7
# Combinedx=5x=$(( x + 1 ))echo $x # 6Comparison
Section titled “Comparison”# Returns 1 (false) or 0 (true)echo $(( 5 > 3 )) # 1echo $(( 5 < 3 )) # 0echo $(( 5 == 5 )) # 1echo $(( 5 != 3 )) # 1
# In conditionsif (( 5 > 3 )); then echo "True"fiWord Splitting
Section titled “Word Splitting”IFS (Internal Field Separator)
Section titled “IFS (Internal Field Separator)”# Default: space, tab, newlinetext="one two three"for word in $text; do echo "$word"done
# Custom IFStext="one:two:three"IFS=':' read -ra words <<< "$text"echo "${words[0]}" # oneSplitting Rules
Section titled “Splitting Rules”# Word splitting after expansionvar="hello world"echo $var # hello world (split into two)echo "$var" # hello world (single)
# Multiple spacesvar="one two three"echo $var # one two threeecho "$var" # one three spacesPathname Expansion
Section titled “Pathname Expansion”Wildcards
Section titled “Wildcards”# * - Any charactersls *.txt
# ? - Single characterls file?.txt
# [] - Character classls file[0-9].txtls file[a-z].txt
# Extended globbing (shopt -s extglob)ls @(foo|bar).txt # foo or barls !(foo).txt # anything except fools *(foo).txt # zero or morels +(foo).txt # one or morels?(foo).txt # zero or oneQuote Removal
Section titled “Quote Removal”Types of Quotes
Section titled “Types of Quotes”# Double quotes - allow expansionecho "Hello $USER" # Hello username
# Single quotes - literalecho 'Hello $USER' # Hello $USER
# Backslash - escapeecho "Hello \$USER" # Hello $USERecho "Path: \$HOME" # Path: /home/userPractical Examples
Section titled “Practical Examples”File Operations
Section titled “File Operations”# Create multiple filestouch file{1..5}.txt
# Backup filescp file.txt{,.bak}
# Create directoriesmkdir -p project/{src,tests,docs}/{css,js}
# Remove extensionsfor f in *.txt; do mv "$f" "${f%.txt}"doneDate/Time in Filenames
Section titled “Date/Time in Filenames”# Current datefilename="backup_$(date +%Y%m%d).tar.gz"echo $filename
# With timetimestamp=$(date +%Y%m%d_%H%M%S)logfile="app_$timestamp.log"Conditional Variables
Section titled “Conditional Variables”# Use default if not setCONFIG_DIR=${CONFIG_DIR:-/etc/myapp}export CONFIG_DIR
# Set default if not setDATABASE_URL=${DATABASE_URL:=postgresql://localhost:5432/db}Debugging Expansions
Section titled “Debugging Expansions”Using set -x
Section titled “Using set -x”#!/usr/bin/env bash# Enable expansion tracing
set -x
var="hello"echo "$var"
result=$(ls)echo "$result"
set +xUsing echo for Debugging
Section titled “Using echo for Debugging”# Show what expands toecho "Expansion: $var"echo "Arithmetic: $(( 5 + 3 ))"
# Check what glob expands toecho *.txtOrder of Operations
Section titled “Order of Operations”┌────────────────────────────────────────────────────────────────┐│ Order of Shell Expansions │├────────────────────────────────────────────────────────────────┤│ ││ Input: echo {a,b}$VAR$(date)*.txt ││ ││ Step 1: Brace Expansion ││ ───────────────────────────────────── ││ echo a$VAR$(date)*.txt b$VAR$(date)*.txt ││ ││ Step 2: Tilde Expansion ││ ───────────────────────────────────── ││ (if ~ present) ││ ││ Step 3: Parameter, Command, Arithmetic Expansion ││ ───────────────────────────────────── ││ echo avalue2024-01-01*.txt bvalue2024-01-01*.txt ││ ││ Step 4: Word Splitting ││ ───────────────────────────────────── ││ (if unquoted) ││ ││ Step 5: Pathname Expansion ││ ───────────────────────────────────── ││ echo avalue2024-01-01file1.txt file2.txt ││ bvalue2024-01-01file1.txt file2.txt ││ ││ Step 6: Quote Removal ││ ───────────────────────────────────── ││ (quotes removed) ││ │└────────────────────────────────────────────────────────────────┘Summary
Section titled “Summary”In this chapter, you learned:
- ✅ Types of shell expansion
- ✅ Brace expansion for generating sequences
- ✅ Tilde expansion for home directories
- ✅ Parameter expansion with advanced features
- ✅ Command substitution
- ✅ Arithmetic expansion
- ✅ Word splitting and IFS
- ✅ Pathname expansion (globbing)
- ✅ Quote removal
- ✅ Practical examples
- ✅ Debugging expansions
Next Steps
Section titled “Next Steps”Continue to the next chapter to learn about Parameter Expansion in detail.
Previous Chapter: Environment Variables Next Chapter: Parameter Expansion