Advanced Expansions and Shell Options
Prerequisites: String manipulation, Arrays
Bash has shell options (shopt) and expansions that make file handling
safer and scripts more flexible.
nullglob: unmatched patterns expand to nothing
for f in *.pdf; do echo "processing $f"; done
echo "---"
shopt -s nullglob
for f in *.pdf; do echo "processing $f"; done
echo "no PDFs, so the loop didn't run"
processing *.pdf
---
no PDFs, so the loop didn't run
Without nullglob, the loop runs once with the literal text *.pdf.
globstar: ** matches folders recursively
shopt -s globstar
mkdir -p src/a/b
touch src/main.sh src/a/util.sh src/a/b/deep.sh src/readme.md
for f in src/**/*.sh; do echo "$f"; done
src/a/b/deep.sh
src/a/util.sh
src/main.sh
extglob: richer patterns
shopt -s extglob
touch app.js app.min.js style.css style.min.css index.html
echo !(*.min.*)
echo *.@(js|css)
app.js index.html style.css
app.js app.min.js style.css style.min.css
| Pattern | Matches |
|---|---|
!(pattern) |
anything except pattern |
@(a|b) |
exactly one of the patterns |
+(pattern) |
one or more |
?(pattern) |
zero or one |
Indirect references and namerefs
color_primary="blue"
key="color_primary"
echo "${!key}"
set_default() {
local -n ref=$1
ref=${ref:-"$2"}
}
unset timeout
set_default timeout 30
echo "timeout=$timeout"
blue
timeout=30
${!key}expands the variable named bykey.local -n ref=$1makesrefa nameref — another name for the variable whose name was passed in, so the function can change the caller's variable (Bash 4.3+).
Transformations (Bash 4.4+)
name="ada lovelace"
echo "${name@u}"
value="it's done"
echo "${value@Q}"
Ada lovelace
'it'\''s done'
${var@u} capitalizes the first letter (Bash 5.1+); ${var@Q} quotes a
value so it can be safely reused as shell input.
Common mistakes
- Turning on
nullglobglobally in scripts that pass patterns to other commands (ls *.logwith no matches becomesls, listing everything). Enable it only around the loops that need it.