参数展开

参数展开是 Shell 处理变量的核心机制。除了基本的 ${var},还有默认值设置、字符串截取、替换、大小写转换等高级用法。熟练掌握参数展开,能让脚本更简洁高效。

基本用法

name="张三"
echo $name
echo ${name}

${name}$name 更明确,推荐使用。

默认值

${var:-default}

变量不存在或为空时,返回默认值:

name=${1:-"匿名"}
echo "你好,$name"

port=${PORT:-8080}
echo "端口:$port"

${var:=default}

变量不存在或为空时,赋值并返回:

: ${config:="/etc/app.conf"}
echo "配置文件:$config"

: 是空命令,用于执行变量赋值。

${var:+value}

变量存在且非空时,返回 value:

debug=${DEBUG:+1}
echo "调试模式:$debug"

${var:?message}

变量不存在或为空时,输出错误信息并退出:

: ${API_KEY:?请设置 API_KEY 环境变量}

字符串长度

str="Hello World"
echo ${#str}

运行结果:

11

子字符串

${var:offset}

从 offset 位置开始截取:

str="Hello World"
echo ${str:6}

运行结果:

World

${var:offset:length}

从 offset 位置开始截取 length 个字符:

str="Hello World"
echo ${str:0:5}
echo ${str:6:5}

运行结果:

Hello
World

负数表示从末尾开始:

str="Hello World"
echo ${str: -5}
echo ${str: -5:3}

运行结果:

World
Wor

注意冒号后要有空格。

删除匹配

${var#pattern}

从开头删除最短匹配:

path="/usr/local/bin/python"
echo ${path#*/}

运行结果:

usr/local/bin/python

${var##pattern}

从开头删除最长匹配:

path="/usr/local/bin/python"
echo ${path##*/}

运行结果:

python

${var%pattern}

从末尾删除最短匹配:

file="document.txt.bak"
echo ${file%.*}

运行结果:

document.txt

${var%%pattern}

从末尾删除最长匹配:

file="document.txt.bak"
echo ${file%%.*}

运行结果:

document

实用示例

file="/home/user/document.txt"
filename=${file##*/}
extension=${file##*.}
basename=${filename%.*}
dir=${file%/*}

echo "文件名:$filename"
echo "扩展名:$extension"
echo "基本名:$basename"
echo "目录:$dir"

替换

${var/pattern/replacement}

替换第一个匹配:

str="hello world world"
echo ${str/world/WORLD}

运行结果:

hello WORLD world

${var//pattern/replacement}

替换所有匹配:

str="hello world world"
echo ${str//world/WORLD}

运行结果:

hello WORLD WORLD

${var/#pattern/replacement}

替换开头的匹配:

str="hello world"
echo ${str/#hello/HELLO}

运行结果:

HELLO world

${var/%pattern/replacement}

替换末尾的匹配:

str="hello world"
echo ${str/%world/WORLD}

运行结果:

hello WORLD

大小写转换

${var^}

首字母大写:

str="hello"
echo ${str^}

${var^^}

全部大写:

str="hello"
echo ${str^^}

${var,}

首字母小写:

str="HELLO"
echo ${str,}

${var,,}

全部小写:

str="HELLO"
echo ${str,,}

变量名操作

${!prefix*}

匹配前缀的变量名:

PATH1="/usr"
PATH2="/bin"
PATH3="/home"
echo ${!PATH*}

运行结果:

PATH PATH1 PATH2 PATH3

${!prefix@}

同上,但以数组形式返回。

${!var}

间接引用:

name="张三"
var="name"
echo ${!var}

运行结果:

张三

数组操作

arr=(a b c d e)

echo ${arr[0]}
echo ${arr[@]}
echo ${#arr[@]}
echo ${arr[@]:1:3}
echo ${arr[@]/a/A}

实用示例

提取文件信息

file="/data/backup/app_20240315.tar.gz"

filename=${file##*/}
basename=${filename%%.*}
extension=${filename#*.}
dir=${file%/*}

echo "文件名:$filename"
echo "基本名:$basename"
echo "扩展名:$extension"
echo "目录:$dir"

参数处理

host=${HOST:-localhost}
port=${PORT:-8080}
user=${USER:-$USER}
password=${PASSWORD:?请设置密码}

字符串处理

str="  Hello World  "

str=${str# }
str=${str% }
str=${str,,}
str=${str// /_}

echo "$str"

路径处理

for file in *.txt; do
    base=${file%.txt}
    mv "$file" "${base}.md"
done

小结

  • ${var:-default} 设置默认值
  • ${#var} 获取字符串长度
  • ${var:offset:length} 截取子字符串
  • ${var#pattern} ${var%pattern} 删除匹配
  • ${var/pattern/replacement} 替换匹配
  • ${var^^} ${var,,} 大小写转换
  • ${!var} 间接引用