在日常脚本和命令行操作中,处理字符串是最频繁的需求之一。Bash 和其他 Shell 内置了若干参数扩展功能,可以直接对变量中的字符串进行截取、替换和长度计算,无需调用 awk、sed 等外部命令,执行速度快且写法紧凑。
1. 长度计算
获取一个字符串的长度,使用 ${#变量名}:
str="Hello World"
echo ${#str} # 输出 11
这对验证输入长度、计算字段偏移等场景非常实用。
2. 子串截取
格式为 ${变量名:起始位置:长度}。位置从 0 开始计数,可以省略长度表示截取到末尾。
str="LinuxBasics"
echo ${str:0:5} # 输出 Linux
echo ${str:5:5} # 输出 Basic
echo ${str:5} # 输出 Basics(从索引5到末尾)
如果使用负数起始位置,注意冒号前需要加空格或括号,以避免与默认值语法混淆:
echo ${str:(-5):3} # 从倒数第5个字符开始取3个,输出 asi
3. 内容替换
- 替换首次匹配:
${变量/旧字符串/新字符串} - 替换全部匹配:
${变量//旧字符串/新字符串} - 删除匹配的前缀或后缀:用替换语法将匹配内容置空即可。
text="foo bar foo baz"
echo ${text/foo/FOO} # 替换第一个foo:FOO bar foo baz
echo ${text//foo/FOO} # 替换所有foo:FOO bar FOO baz
path="/home/user/docs/report.txt"
echo ${path#*/} # 删除最短匹配前缀(*/):home/user/docs/report.txt
echo ${path##*/} # 删除最长匹配前缀(*/):report.txt
echo ${path%/*} # 删除最短匹配后缀(/*):/home/user/docs
echo ${path%%/*} # 删除最长匹配后缀(/*):(空)
在上述例子中,# 用于删除前缀(从字符串左侧匹配),% 用于删除后缀(从右侧匹配),单符号表示最短匹配,双符号表示最长匹配。这种模式常用于提取文件名、目录路径或修改扩展名:
filename="archive.tar.gz"
echo ${filename%.*} # archive.tar
echo ${filename%%.*} # archive
4. 截取指定字符前后的内容
除了单纯的位置截取,还可以通过间接替换实现更灵活的抽取。例如,取出 IP 地址中前两段:
ip="192.168.1.100"
first_two=${ip%.*.*} # 删除从右侧起第二个点及之后的内容,得到 192.168
若想提取域名中的顶级域:
host="www.example.com"
tld=${host##*.} # 删除最长前缀直到最后一个点,得到 com
为什么推荐内置参数扩展?
- 性能:参数扩展完全在 Shell 内部完成,不需要启动外部进程。
- 简洁:一行代码即可完成常见操作,可读性高。
- 可移植:这些语法适用 Bash、Zsh 等主流 Shell,在脚本中广泛使用。
掌握这些字符串处理技巧后,大量原本需要管道组合 cut、sed 或 awk 的简单操作,都可以用更轻量的方式实现,让脚本更加高效易读。