# Parameter Expansion, Command Substitution and Arithmetic — Bash / Shell Scripting

Source: https://www.skillbyai.com/en/bash/v-expansion

> Transform strings and compute values without external tools.

## Built-in string and number operations

Bash can transform variables without calling `sed` or `cut`. **Defaults**: `${var:-fallback}` uses a fallback if `var` is unset or empty; `${var:=fallback}` also assigns it; `${var:?message}` exits with an error if it is missing, a neat way to require variables. **Length**: `${#var}`. **Removing prefixes and suffixes**: `${path#*/}` removes the shortest match of `*/` from the start, `${path##*/}` the longest (giving the file name), `${file%.*}` removes the shortest suffix match (dropping an extension), `${file%%.*}` the longest. **Replacement**: `${var/old/new}` replaces the first match, `${var//old/new}` all matches. **Substrings**: `${var:offset:length}`. **Case** (Bash 4+): `${var^^}` upper, `${var,,}` lower. **Command substitution** `$(command)` captures a command's output (trailing newlines removed); prefer it to old backticks. **Arithmetic expansion** `$(( expression ))` does integer maths: `$(( count + 1 ))`, `$(( size / 1024 ))`; Bash has no floating point, so use `awk` or `bc` when you need decimals.

## Expansions in practice

Each line uses a built-in expansion instead of an external command.

```bash
path="/var/backups/db/shop-2026-10-03.sql.gz"

echo "${path##*/}"          # shop-2026-10-03.sql.gz   (basename)
echo "${path%/*}"           # /var/backups/db          (dirname)
name="${path##*/}"
echo "${name%%.*}"          # shop-2026-10-03          (strip all extensions)
echo "${name/2026/2027}"     # replace first match

: "${DB_HOST:?DB_HOST must be set}"   # exit with a message if missing
port="${DB_PORT:-5432}"

files=$(ls /var/backups/db | wc -l)
echo "backups: $files, next number: $(( files + 1 ))"
echo "upper: ${name^^}"
```

## Prefer built-ins in loops

Calling `basename`, `dirname` or `sed` once per iteration over thousands of files starts thousands of processes. Parameter expansion does the same work inside Bash, often dozens of times faster.

**Quiz:** With file="report.tar.gz", what does `${file%.*}` produce?

- [x] report.tar
- [ ] report
- [ ] tar.gz
- [ ] gz

*Answer:* report.tar. % removes the shortest matching suffix, so only ".gz" is removed.
