Bash 參數擴展提供強大的模式匹配刪除與替換功能,無需外部 sed/awk/perl 即可完成字串處理,效能極高且語法簡潔。本文系統整理 #、##、%、%%、/、// 六大操作符,配合通配符與貪婪/非貪婪模式,涵蓋路徑處理、檔名解析、環境變數清理等實戰場景。

| 語法 | 方向 | 匹配模式 | 範例 | 結果 |
|---|---|---|---|---|
${var#pattern} | 左→右 | 最短匹配 (非貪婪) | PATH=/usr/bin:/bin${PATH#*/} | /bin |
${var##pattern} | 左→右 | 最長匹配 (貪婪) | ${PATH##*/} | bin |
${var%pattern} | 右→左 | 最短匹配 | FILE=archive.tar.gz${FILE%.*} | archive.tar |
${var%%pattern} | 右→左 | 最長匹配 | ${FILE%%.*} | archive |
| 語法 | 範圍 | 範例 | 結果 |
|---|---|---|---|
${var/pattern/repl} | 首次匹配 | STR="foo bar foo"${STR/foo/FOO} | FOO bar foo |
${var//pattern/repl} | 全域替換 | ${STR//foo/FOO} | FOO bar FOO |
${var/#pattern/repl} | 前綴匹配替換 | ${PATH/#/usr/local} | 替換開頭 |
${var/%pattern/repl} | 後綴匹配替換 | ${FILE/%.gz/.bz2} | 替換副檔名 |
FILE="/home/user/docs/report.txt"
DIR=${FILE%/*} # /home/user/docs
BASE=${FILE##*/} # report.txt
EXT=${FILE##*.} # txt
NAME=${BASE%.*} # report
# 移除 PATH 中重複/空路徑
clean_path() {
local p=$1 IFS=: dir
for dir in $p; do
[ -d "$dir" ] && printf "%s:" "$dir"
done | sed 's/:$//'
}
export PATH=$(clean_path "$PATH")
for f in *.jpg; do
mv "$f" "${f%.jpg}.png"
done
case $VAR in
/*) echo "絕對路徑" ;;
.*) echo "相對路徑" ;;
*:) echo "以冒號結尾" ;;
esac
# 等價於
[[ $VAR == /* ]] && echo "絕對路徑"
[[ $VAR == *: ]] && echo "以冒號結尾"
shopt -s extglob
# +(pattern) 一次或多次
# *(pattern) 零次或多次
# ?(pattern) 零次或一次
# @(p1|p2) 擇一
# !(pattern) 非匹配
VAR="prefix_foo_bar_suffix"
echo ${VAR/#prefix_@(foo|bar)_/} # 刪除 prefix_foo_ 或 prefix_bar_
echo ${VAR/%_@(foo|bar)_suffix/} # 刪除 _foo_suffix 或 _bar_suffix
# 內建參數擴展 (最快)
time for i in {1..100000}; do ${VAR#*/}; done
# real 0.02s
# 外部 sed
time for i in {1..100000}; do echo $VAR | sed 's|^[^/]*/||'; done
# real 12.5s
參數擴展在循環中處理大量字串時效能優勢明顯。
/ 需轉義或改用其他分隔符:${VAR//\//_}。${var-name} 為預設值語法,勿混淆。${arr[0]##*/}。#、##、%、%%,/、// 為 Bash/ksh/zsh 擴展。熟練運用參數擴展,能讓 Shell 腳本更簡潔、高效、可移植,是進階 Shell 程式設計的核心技能。