Variable Tricks

bash has this whole parameter expansion system built in and honestly it’s kinda ugly looking but incredibly useful once you get the pattern down. no need to pipe to sed or awk for basic string stuff.

path manipulation

this is the one I reach for most. say you have:

file="/home/user/docs/report.tar.gz"
${file##*/}    # report.tar.gz   (just the filename)
${file%/*}     # /home/user/docs  (just the directory)
${file%.*}     # /home/user/docs/report.tar  (drop last extension)
${file%%.*}    # /home/user/docs/report      (drop ALL extensions)
${file##*.}    # gz  (just the extension)

the trick to remembering: # chops from the left, % chops from the right. double means greedy. I still have to think about it sometimes tbh.

string stuff

replace things:

msg="hello world"
${msg/world/bash}     # hello bash  (first match)
${msg//o/0}           # hell0 w0rld (all matches)

substring:

str="abcdefgh"
${str:2:4}   # cdef
${str:5}     # fgh
${#str}      # 8 (length)

case conversion (bash 4+):

name="hello"
${name^}     # Hello (first letter)
${name^^}    # HELLO (all)

defaults — this is the good stuff

instead of writing if [ -z "$PORT" ] everywhere:

${PORT:-8080}              # use 8080 if PORT is empty/unset
${PORT:=8080}              # same but also SET it
${DB_HOST:?'not set!'}     # crash with error if missing
${DEBUG:+'--verbose'}      # use '--verbose' only if DEBUG IS set

the := one is great for scripts with optional config. the :? one is great for scripts with required config. I use both all the time.

arrays

fruits=(apple banana cherry)
${fruits[0]}       # apple
${fruits[@]}       # all of them
${#fruits[@]}      # 3
${fruits[@]:1:2}   # banana cherry (slice)

remember if you’re on zsh interactively, arrays start at 1 there. but #!/bin/bash scripts are always 0-indexed. don’t let that bite you.


see also: bash-brace-expansion, bash-quick-loops, bash-history-expansion

gnu manual on parameter expansion — bookmark this one, it’s dense but complete

the bash hackers wiki had a great page on this too (archived now sadly)