字符串操作
Shell 字符串操作:切片、长度与替换技巧
在 Shell 脚本中,字符串处理是日常任务的重要组成部分,包括提取子串、计算长度、替换内容等。掌握这些操作能帮助你高效处理文本数据,如日志分析、配置解析等。本文详细讲解 Shell 中常用的字符串操作方法。
字符串切片:提取子字符串
字符串切片用于从指定位置开始提取部分字符,Shell 提供了两种灵活的切片语法,下标从 0 开始(第一个字符为位置 0)。
从指定位置截取到结尾
语法:${变量:起始位置}
- 从
起始位置开始,截取到字符串末尾的所有字符。 - 若
起始位置为负数(需用括号包裹),表示从字符串末尾倒数计算。
示例:
str="abcdefgh"
# 从位置 2 开始截取(包含位置 2)
echo ${str:2} # 输出:cdefgh
# 从位置 5 开始截取
echo ${str:5} # 输出:fgh
# 从末尾倒数第 3 个位置开始(等价于长度-3)
echo ${str:(-3)} # 输出:fgh(注意负数需用括号)
截取指定长度的子串
语法:${变量:起始位置:长度}
- 从
起始位置开始,截取指定长度的字符(若剩余字符不足,则截取到结尾)。
示例:
str="123456789"
# 从位置 2 开始,截取 4 个字符
echo ${str:2:4} # 输出:3456
# 从位置 5 开始,截取 10 个字符(实际不足,截取到结尾)
echo ${str:5:10} # 输出:6789
# 从倒数第 4 个位置开始,截取 2 个字符
echo ${str:(-4):2} # 输出:67
注意:若起始位置超过字符串长度,返回空值;若长度为负数,在 Bash 4.2+ 中表示 “截取到距离末尾 长度 个字符的位置”。
字符串长度:计算字符个数
使用 ${#变量名} 可获取字符串的长度(字符个数),适用于检查输入合法性、限制字符数量等场景。
示例:
# 普通字符串
name="Shell"
echo ${#name} # 输出:5
# 含空格的字符串
sentence="Hello World"
echo ${#sentence} # 输出:11(包含空格)
# 空字符串
empty=""
echo ${#empty} # 输出:0
# 实际应用:检查输入长度
read -p "请输入密码(至少6位):" passwd
if [ ${#passwd} -lt 6 ]; then
echo "密码长度不足!"
fi
字符串替换:修改匹配内容
Shell 支持两种替换模式:替换第一个匹配项和替换所有匹配项,无需依赖 sed 等外部工具。
替换第一个匹配项
语法:${变量/旧字符串/新字符串}
- 仅替换字符串中第一个与
旧字符串匹配的部分。
示例:
path="/usr/local/bin:/usr/bin:/bin"
# 替换第一个 ":" 为 ";"
echo ${path/:/;} # 输出:/usr/local/bin;/usr/bin:/bin
# 替换第一个 "usr" 为 "USER"
echo ${path/usr/USER} # 输出:/USER/local/bin:/usr/bin:/bin
替换所有匹配项
语法:${变量//旧字符串/新字符串}
- 替换字符串中所有与
旧字符串匹配的部分(双斜杠//表示全局替换)。
示例:
str="a,b,c,d"
# 替换所有 "," 为 "|"
echo ${str//,/|} # 输出:a|b|c|d
# 替换所有 "a" 为空(删除所有 "a")
text="abacada"
echo ${text//a/} # 输出:bc d(连续的a被删除)
条件性替换
- 替换开头匹配项:
${变量/#旧字符串/新字符串}(仅替换字符串开头的匹配项)。 - 替换结尾匹配项:
${变量/%旧字符串/新字符串}(仅替换字符串结尾的匹配项)。
示例:
file="report.txt.bak"
# 替换开头的 "report" 为 "log"
echo ${file/#report/log} # 输出:log.txt.bak
# 替换结尾的 "bak" 为 "backup"
echo ${file/%bak/backup} # 输出:report.txt.backup
实际应用案例
解析文件路径
file_path="/home/user/docs/report.pdf"
# 提取文件名(含扩展名)
filename=${file_path##*/}
echo "文件名:$filename" # 输出:report.pdf
# 提取扩展名(利用替换)
ext=${filename#*.}
echo "扩展名:$ext" # 输出:pdf
# 提取文件名(不含扩展名)
name=${filename%.*}
echo "纯文件名:$name" # 输出:report
(注:## 和 # 是贪婪 / 非贪婪删除前缀的操作,%% 和 % 是删除后缀的操作,本质是特殊的替换形式)
处理用户输入
# 标准化用户输入的姓名(首字母大写,其余小写)
read -p "请输入姓名:" name
# 提取首字母并大写(结合 tr 命令)
first=${name:0:1}
first_upper=$(echo $first | tr 'a-z' 'A-Z')
# 提取剩余字符并小写
rest=${name:1}
rest_lower=$(echo $rest | tr 'A-Z' 'a-z')
# 合并结果
standard_name="$first_upper$rest_lower"
echo "标准化姓名:$standard_name"
执行效果:
请输入姓名:jOhN
标准化姓名:John