Skip to content

$ cat ./posts/bash/parameter-expansion-worth-memorising.sh

-rw-r--r-- 1.6K #bash

Parameter expansion worth memorising

by chris · 2 min read · /bash


Every fork costs about a millisecond. In a loop over ten thousand filenames, replacing basename with parameter expansion is the difference between a script that finishes and one you cancel. More importantly, the expansion is easier to read once you know it.

1. Trimming

path=/var/log/nginx/access.log

echo "${path##*/}"    # access.log      — longest match from the front
echo "${path%/*}"     # /var/log/nginx  — shortest match from the back
echo "${path##*.}"    # log
echo "${path%.*}"     # /var/log/nginx/access

One # or % is a short match, two is greedy. The symbols sit either side of the dollar sign on a keyboard, which is the mnemonic that finally made it stick for me.

2. Defaults and assertions

: "${PORT:=8080}"        # assign if unset or empty
: "${TOKEN:?is required}" # abort with a message
echo "${DEBUG:-off}"      # use a fallback without assigning

3. Substitution and case

name=deploy-prod-api
echo "${name//-/_}"   # deploy_prod_api — replace all
echo "${name/-/_}"    # deploy_prod-api — replace first
echo "${name^^}"      # DEPLOY-PROD-API
echo "${#name}"       # 15

4. Where it stops

Parameter expansion has no regular expressions, only globs. The moment you need a capture group, reach for [[ $var =~ re ]] and read BASH_REMATCH, or accept the fork and use sed. Bending a glob into doing a regex’s job produces the kind of line that nobody, including its author, can modify six months later.

← cd .. fris@linux:~/blog$ man bash