第34课:字符串操作与参数展开
所属模块: Shell 基础
难度: Intermediate
标签: strings, expansion
上一课: 第33课 - 环境变量与 export
下一课: 第35课 - if 条件判断
1. 学习目标
完成本课学习后,你将能够:
- 掌握 Bash 中常用的字符串操作,如获取长度、截取子串。
- 熟练使用参数展开(Parameter Expansion)进行变量值的查找、替换、删除等高级操作。
- 理解并运用模式匹配(Pattern Matching)来增强字符串处理能力。
- 能够组合使用这些技术,编写更强大、更简洁的 Shell 脚本来处理文本和文件名。
2. 核心概念
在 Shell 编程中,变量和字符串是数据处理的核心。除了简单的赋值和引用,Bash 提供了一系列强大的“工具箱”来处理变量内容,这就是参数展开。它允许我们在变量被引用时,对其值进行各种变换,而无需启动外部程序(如 grep, sed, awk),效率更高,代码也更简洁。
2.1 字符串长度与截取
- 获取长度:
${#variable}。这会返回变量variable中字符的个数。 - 截取子串:
${variable:offset:length}。从变量值中,从offset(偏移量,从0开始计数)位置起,提取length个字符。length可省略,表示提取到末尾。- 类比: 想象字符串是一根绳子,
${var:5:3}就是从绳子第6个结(偏移量5)开始,量出3个结的长度剪下来。
- 类比: 想象字符串是一根绳子,
2.2 参数展开之查找与替换
这是一组非常强大的操作,语法类似文字处理软件中的“查找替换”,但功能更灵活。
- 查找并替换:
${variable/pattern/replacement}- 只替换第一个匹配
pattern的部分。 ${variable//pattern/replacement}:替换所有匹配的部分。${variable/#pattern/replacement}:如果pattern匹配变量值的开头,则替换。${variable/%pattern/replacement}:如果pattern匹配变量值的末尾,则替换。- 注意:
pattern支持通配符(*,?,[...])。
- 只替换第一个匹配
2.3 参数展开之删除
使用 #, % 符号来删除变量值的一部分。
- 从开头删除(最短匹配):
${variable#pattern}- 删除变量值开头与
pattern匹配的最短部分。
- 删除变量值开头与
- 从开头删除(最长匹配):
${variable##pattern}- 删除变量值开头与
pattern匹配的最长部分。
- 删除变量值开头与
- 从末尾删除(最短匹配):
${variable%pattern}- 删除变量值末尾与
pattern匹配的最短部分。
- 删除变量值末尾与
- 从末尾删除(最长匹配):
${variable%%pattern}- 删除变量值末尾与
pattern匹配的最长部分。 - 记忆口诀:
#号像键盘上的Home键,处理开头;%号像键盘上的End键,处理末尾。单符号(#,%)是最短匹配(保守删除),双符号(##,%%)是最长匹配(贪婪删除)。
- 删除变量值末尾与
3. 代码示例
以下示例在 Bash Shell 中可直接运行,请仔细阅读注释。
#!/bin/bash
# === 基础字符串操作 ===
str="Hello, World! This is a string."
echo "原始字符串: '$str'"
echo "字符串长度: ${#str}"
# 截取子串:从偏移量7开始(第一个字符偏移量为0),截取5个字符
echo "截取 'World': ${str:7:5}"
# 截取子串:从偏移量13开始,截取到末尾
echo "截取后半部分: ${str:13}"
# === 参数展开:查找与替换 ===
my_path="/home/user/documents/report.txt"
echo "原始路径: '$my_path'"
# 替换第一个出现的 'user' 为 'admin'
echo "替换第一个user: ${my_path/user/admin}"
# 替换所有出现的 '/' 为 '|' (注意转义反斜杠)
echo "替换所有斜杠: ${my_path//\//|}"
# 仅当字符串以 '/home' 开头时,替换为 '/data'
echo "替换开头: ${my_path/#/home//data}"
# 仅当字符串以 '.txt' 结尾时,替换为 '.log'
echo "替换后缀: ${my_path/%.txt/.log}"
# === 参数展开:删除操作(常用于处理文件路径和扩展名)===
file_name="archive.backup.tar.gz"
echo "文件名: '$file_name'"
# 从末尾删除最短匹配的 '.gz' (获取去掉最后.gz的文件名)
echo "去掉 .gz: ${file_name%.*}"
# 从末尾删除最长匹配的 '.*' (获取去掉所有扩展名的文件名)
echo "去掉所有扩展名: ${file_name%%.*}"
# 从开头删除最短匹配的 '*.' (获取最后一个扩展名)
echo "获取最后扩展名: ${file_name##*.}"
# 实用场景:获取脚本自身所在目录(不带脚本名)
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "当前脚本目录: '$script_dir'"
# 实用场景:安全地设置变量默认值
unset unset_var
echo "变量未设置时使用默认值: '${unset_var:-Default Value}'"
4. 实践练习
练习 1:基础截取
给定一个字符串 quote="The quick brown fox jumps over the lazy dog"。
- 编写一行代码,打印出该字符串的长度。
- 编写一行代码,截取出单词
"brown"。 - 编写一行代码,截取出从
"jumps"开始到字符串结尾的内容。
练习 2:文件名处理
假设有一个变量 file="my_script.backup.sh"。
- 使用参数展开,提取出不带任何扩展名的基文件名(即
my_script)。 - 使用参数展开,将文件名中的第一个
.backup部分删除(结果应为my_script.sh)。
练习 3:模拟日志路径转换(综合应用)
你有一些旧的服务器日志路径,格式为 /var/log/oldapp/access-2023-10-01.log.gz。
你需要将它们转换为新的存储路径格式:/data/logs/newapp/2023-10-01/access.log。
请使用参数展开完成以下转换(假设变量 old_path 已存储旧路径):
- 提取日期部分(如
2023-10-01)。 - 构造新路径。
你可以先尝试为
old_path="/var/log/oldapp/access-2023-10-01.log.gz"编写转换代码。
5. 常见错误
- 偏移量计数错误: 记住偏移量从 0 开始,而不是 1。
${var:1}提取的是从第二个字符开始的内容。 - 混淆
#,%和##,%%:- 对于字符串
file.tar.gz: ${file%.*}结果是file.tar(最短匹配,删除末尾的.*即最后一个.gz)。${file%%.*}结果是file(最长匹配,删除末尾的.*即.tar.gz)。- 需要根据你想要保留还是删除的部分来谨慎选择。
- 对于字符串
- 忘记双引号: 在模式匹配和替换中,如果变量包含空格或特殊字符,用双引号将变量括起来是更安全的做法,例如
"${var// /_}"。但对于#,%删除操作,模式中的通配符即使加了引号也可能被解释,具体行为取决于 Shell 选项,通常直接使用即可。 - 贪婪匹配的意外结果: 使用
##或%%进行贪婪匹配时要格外小心,它可能会删除比你预期多得多的内容。先在小例子上测试。
6. 小结
本节课我们深入学习了 Bash 中非常实用的字符串处理技巧:
- 基础操作: 使用
${#var}获取长度,${var:offset:length}截取子串。 - 参数展开的精髓: 允许我们在引用变量的同时对其值进行“二次加工”。
- 替换:
${var/pattern/repl}及其变体。 - 删除:
${var#pattern},${var##pattern},${var%pattern},${var%%pattern}。记住#管开头,%管结尾。
- 替换:
- 核心价值: 这些操作是 Shell 内建的,执行速度快,是编写高效、简洁运维脚本(如批量文件重命名、日志分析、路径构造)的必备技能。
熟练掌握字符串操作与参数展开,将极大提升你编写 Shell 脚本处理文本和数据的灵活性和能力。
练习编辑器
rust
Loading...