5.3. Parameter Substitution#
Parameter substitution is bash’s way of doing sophisticated variable operations without calling external programs. It uses special syntax ${var...} to provide defaults, check if variables exist, extract parts of strings, and more.
This is where bash programming becomes powerful—you can write complex logic entirely with parameter expansion.
5.3.1. Common Pitfalls#
5.3.1.1. ❌ Forgetting Braces#
# WRONG
$ echo $var#pattern # Just prints variable, ignores #pattern
# RIGHT
$ echo ${var#pattern}
5.3.1.2. ❌ Pattern Syntax#
$ filename="document.txt"
# WRONG: Literal dot
$ echo ${filename%.txt}
document # Matched "txt" not ".txt"
# RIGHT: Escape the dot or use different pattern
$ echo ${filename#*.}
txt
# Or be more specific
$ base="${filename%.*}"
5.3.1.3. ❌ Substring With Wrong Syntax#
# WRONG
$ echo $text[0:3]
# RIGHT
$ echo ${text:0:3}
5.3.2. When to Use Parameter Substitution#
Use when:
You need defaults for optional parameters
You’re extracting parts of filenames/paths
You need string manipulation without external commands
You want error messages for missing variables
Don’t use when:
The operation is complex (use sed/awk instead)
You need regex (grep is better)
It makes code hard to read
# ✓ Good use: simple default
filename="${1:-default.txt}"
# ✗ Overuse: confusing nesting
result="${${var#prefix}%suffix}"
# Better:
temp="${var#prefix}"
result="${temp%suffix}"
5.3.3. All Parameter Substitution Patterns#
Syntax |
Meaning |
|---|---|
|
Default if unset |
|
Default if unset, and assign |
|
Error if unset |
|
Substitute if set |
|
Length of value |
|
Remove shortest prefix |
|
Remove longest prefix |
|
Remove shortest suffix |
|
Remove longest suffix |
|
Replace first |
|
Replace all |
|
Replace at start |
|
Replace at end |
|
Extract substring |
|
Convert to uppercase |
|
Convert to lowercase |
5.3.4. Complex Examples#
5.3.4.1. Parse URL#
url="https://user:pass@example.com:8080/path"
# Extract protocol
protocol="${url%%://*}" # https
# Remove protocol
rest="${url#*://}" # user:pass@example.com:8080/path
# Extract host (remove user info)
host="${rest#*@}" # example.com:8080/path
# Extract just domain
domain="${host%%:*}" # example.com
# Extract path
path="${rest#*/}" # path
5.3.4.2. Generate Backup Filename#
filename="data.csv"
timestamp=$(date +%Y%m%d_%H%M%S)
# Remove extension, add timestamp and restore extension
backup="${filename%.*}.${timestamp}.${filename##*.}"
echo $backup
# Output: data.20250115_103045.csv
5.3.4.3. Validate and Set Defaults#
#!/bin/bash
# Command line arguments with defaults
input_file="${1:?Input file required}"
output_file="${2:-output.txt}"
format="${3:-json}"
echo "Input: $input_file"
echo "Output: $output_file"
echo "Format: $format"
5.3.5. String Conversion#
Convert to uppercase or lowercase (bash 4+):
$ name="Alice"
# Convert to uppercase
$ echo ${name^^}
ALICE
# Convert to lowercase
$ echo ${name,,}
alice
# Capitalize first letter
$ echo ${name^}
Alice
# Lowercase first letter
$ echo ${name,}
alice
5.3.6. Extract Substrings#
Get a portion of a string:
# Extract 3 characters starting at position 0
$ text="hello"
$ echo ${text:0:3}
hel
# Extract starting at position 1
$ echo ${text:1}
ello
# Extract 2 characters starting at position 1
$ echo ${text:1:2}
el
# Negative offsets (from end)
$ echo ${text: -3}
llo
# From 3 characters before the end
5.3.7. String Length#
Get the length of a variable:
$ password="secret"
$ echo ${#password}
6
$ path="/home/alice/documents/file.txt"
$ echo ${#path}
30
# Useful for validation
if [ ${#password} -lt 8 ]; then
echo "Password too short"
fi
5.3.8. Finding and Replacing#
Replace parts of a string:
5.3.8.1. Replace First Match#
$ text="the cat in the hat"
$ echo ${text/the/a}
a cat in the hat
# Only first "the" replaced
$ text="foo.old.old"
$ echo ${text/old/new}
foo.new.old
# Only first "old" replaced
5.3.8.2. Replace All Matches#
$ text="the cat in the hat"
$ echo ${text//the/a}
a cat in a hat
# All "the" replaced
$ text="foo-bar-baz"
$ echo ${text///-/_}
foo_bar_baz
# All hyphens become underscores
5.3.8.3. Replace at Start or End#
$ text="test123"
# Replace at start (if match)
$ echo ${text/#test/exam}
exam123
# Replace at end (if match)
$ echo ${text/%123/456}
test456
# No match, returns original
$ echo ${text/#foo/bar}
test123
5.3.9. Removing Prefixes and Suffixes#
Remove parts of a string:
5.3.9.1. Remove Prefix#
# Remove shortest matching prefix
$ filename="document.txt"
$ echo ${filename#*.}
txt
# Removes everything up to and including first "."
# Remove longest matching prefix
$ path="/home/alice/documents/file.txt"
$ echo ${path##*/}
file.txt
# Removes everything up to and including last "/"
$ echo ${path#*/}
home/alice/documents/file.txt
# Just first "/" removed
5.3.9.2. Remove Suffix#
# Remove shortest matching suffix
$ filename="document.txt"
$ echo ${filename%.*}
document
# Removes from last "." to end
# Remove longest matching suffix
$ filename="archive.tar.gz"
$ echo ${filename%%.*}
archive
# Removes from first "." to end
$ echo ${filename%.*}
archive.tar
# Just last ".gz" removed
5.3.9.3. Practical Examples#
# Extract filename from path
$ path="/home/alice/documents/file.txt"
$ filename="${path##*/}"
$ echo $filename
file.txt
# Remove extension
$ extension="${filename#*.}"
$ base="${filename%.*}"
$ echo "Base: $base, Extension: $extension"
Base: file, Extension: txt
# Remove directory from path
$ dir="${path%/*}"
$ echo $dir
/home/alice/documents
5.3.10. Default Values#
One of the most useful operations: provide a default if variable is unset or empty.
5.3.10.1. Use Default If Unset#
$ echo ${unset_var:-default}
default
# unset_var doesn't exist, uses "default"
$ var="actual"
$ echo ${var:-default}
actual
# var is set, uses its value
5.3.10.2. Use Default If Empty#
$ var=""
$ echo ${var:-default}
# (empty, var is set even if empty)
$ echo ${var:=default}
default
# Sets var to default and echoes it
# Now var is set
$ echo $var
default
5.3.10.3. Require Variable (Error If Unset)#
$ echo ${var:?Variable must be set}
# If var is unset, displays error and exits
# Useful for required parameters
$ echo ${api_key:?API_KEY not configured}
5.3.11. Basic Syntax#
Parameter substitution uses the brace syntax:
$ var="value"
$ echo $var # Simple expansion
value
$ echo ${var} # Explicit (same as above)
value
$ echo ${var#...} # Remove prefix
$ echo ${var%...} # Remove suffix
$ echo ${var/find/repl} # Find and replace
The braces {} are required for these operations.