Bash string manipulation lives in parameter expansion — no external commands, no subprocesses, just ${var...} doing trims, slices, replacements, and case changes in place. For the string work that used to mean piping through sed, this is the in-process answer.
Trimming from the edges #
Four operators strip from the front (#) or the end (%), each in short and long forms:
$ f="archive.tar.gz"
$ echo "${f#*.}" # shortest match from the front: tar.gz
$ echo "${f##*.}" # longest: gz
$ echo "${f%.*}" # shortest from the end: archive.tar
$ echo "${f%%.*}" # longest: archive
The mnemonic: # sits before % on the keyboard, front before back; doubled means greediest. The canonical uses fall straight out of this table — basename is ${path##*/}, extension stripping is ${file%.*}, and the bulk rename idiom "${f%.jpeg}.jpg" is a single expansion.
Replacing and slicing #
| Form | Result |
|---|---|
${s/old/new} | Replace first match |
${s//old/new} | Replace every match |
${s/#old/new} | Anchor at the start |
${s/%old/new} | Anchor at the end |
${s:2:5} | Substring: offset 2, length 5 |
${s:(-4)} | Last four characters |
$ url="http://old.example.com/x"
$ echo "${url//old.example.com/aospix.com}"
http://aospix.com/x
Substring indexing is zero-based and counts characters, not bytes — with UTF-8 that distinction occasionally matters.
Case and defaults #
Bash 4 added case operators, and the default forms from variables round out the toolkit:
$ echo "${name^}" # capitalize first char
$ echo "${name^^}" # all upper
$ echo "${name,,}" # all lower
$ file="${1:-default.conf}" # default when unset
$ dir="${dir:?need a directory}" # fail loudly instead
When to graduate #
Expansion is ideal for single, simple transforms in scripts. The graduation points are worth naming: patterns involving / need escaping gymnastics, multiple sequential edits get unreadable, and anything involving whole words or character classes is regex work — that is sed and awk territory, or a real language.
The edge-stripping operators pair with globbing (same pattern language); the default forms are strict mode's best friend. The scripting series continues.
