Bash Shell 字符串操作详解
Bash 中的字符串操作是脚本编写的核心技能之一,涵盖定义、拼接、截取、替换、匹配等场景。以下是常见用法及示例:
1. 字符串基础
1.1 定义字符串
1
2
3
|
str1="Hello World" # 双引号(允许变量替换和转义)
str2='Hello $USER' # 单引号(原样输出,不解析变量)
str3=$'Line1\nLine2' # ANSI-C 引号(支持转义字符)
|
1.2 字符串拼接
1
2
3
4
5
6
|
name="Alice"
greet="Hello, "$name"!" # 直接拼接
echo $greet # 输出: Hello, Alice!
# 使用双引号简化
greet="Hello, ${name}!" # 推荐写法
|
1.3 获取字符串长度
1
2
|
str="abcdefg"
echo ${#str} # 输出: 7
|
2. 字符串截取
2.1 按位置截取
| 语法 |
描述 |
示例(str=“abcdef”) |
${str:start} |
从 start 开始截取到末尾 |
${str:2} → “cdef” |
${str:start:length} |
从 start 截取 length 长度 |
${str:1:3} → “bcd” |
2.2 按模式截取
| 语法 |
描述 |
示例(str=“app_log_20231010.txt”) |
${str#pattern} |
删除开头匹配的最短模式 |
${str#*_} → “log_20231010.txt” |
${str##pattern} |
删除开头匹配的最长模式 |
${str##*_} → “20231010.txt” |
${str%pattern} |
删除结尾匹配的最短模式 |
${str%.*} → “app_log_20231010” |
${str%%pattern} |
删除结尾匹配的最长模式 |
${str%%.*} → “app_log” |
3. 字符串替换
3.1 简单替换
| 语法 |
描述 |
示例(str=“hello world hello”) |
${str/old/new} |
替换第一个匹配项 |
${str/hello/Hi} → “Hi world hello” |
${str//old/new} |
替换所有匹配项 |
${str//hello/Hi} → “Hi world Hi” |
3.2 前缀/后缀替换
| 语法 |
描述 |
示例(str=“error.log”) |
${str/#prefix/new} |
替换开头的 prefix |
${str/#error/access} → “access.log” |
${str/%suffix/new} |
替换结尾的 suffix |
${str/%.log/.txt} → “error.txt” |
4. 字符串查找
4.1 查找子字符串位置
1
2
3
|
str="abcdefg"
index=$(expr index "$str" "cde") # 查找子串起始位置
echo $index # 输出: 3(位置从1开始计数)
|
4.2 检查是否包含子串
1
2
3
4
|
str="hello world"
if [[ $str == *"world"* ]]; then
echo "包含 'world'"
fi
|
5. 字符串分割为数组
1
2
3
|
csv="apple,banana,orange"
IFS=',' read -ra arr <<< "$csv" # 按逗号分割
echo "${arr[1]}" # 输出: banana
|
6. 字符串比较
| 操作符 |
描述 |
示例 |
== 或 = |
相等 |
[[ "abc" == "abc" ]] → true |
!= |
不相等 |
[[ "abc" != "def" ]] → true |
> 或 < |
按字典序比较 |
[[ "apple" < "banana" ]] → true |
-z |
字符串为空 |
[[ -z "" ]] → true |
-n |
字符串非空 |
[[ -n "abc" ]] → true |
7. 正则表达式匹配
7.1 使用 =~ 操作符
1
2
3
4
|
email="user@example.com"
if [[ $email =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then
echo "有效邮箱地址"
fi
|
7.2 提取匹配组
1
2
3
4
|
str="Date: 2023-10-10"
if [[ $str =~ ([0-9]{4}-[0-9]{2}-[0-9]{2}) ]]; then
echo "日期: ${BASH_REMATCH[1]}" # 输出: 日期: 2023-10-10
fi
|
8. 高级技巧
8.1 处理带空格的字符串
1
2
3
4
5
6
7
8
9
|
file_path="/path/with spaces/file.txt"
# 双引号保护空格
cp "$file_path" /backup/
# 数组存储带空格字符串
files=("file1.txt" "file two.txt")
for file in "${files[@]}"; do
echo "$file"
done
|
8.2 使用 heredoc 定义多行字符串
1
2
3
4
5
|
cat <<EOF
第一行
第二行
变量替换: $USER
EOF
|
8.3 颜色和格式输出
1
2
3
|
RED='\033[0;31m'
NC='\033[0m' # 重置颜色
echo -e "${RED}错误信息${NC}"
|
9. 实用示例
9.1 获取文件名和扩展名
1
2
3
|
file="image.jpg"
filename="${file%.*}" # image
extension="${file##*.}" # jpg
|
9.2 路径处理
1
2
3
|
path="/var/log/app.log"
dirname="${path%/*}" # /var/log
basename="${path##*/}" # app.log
|
总结
- 核心操作:截取 (
${var:start:len})、替换 (${var/old/new})、模式删除 (${var#pattern})
- 关键技巧:
- 使用
[[ ]] 进行字符串比较和正则匹配
- 用双引号保护含空格的字符串
- 灵活使用
IFS 分割字符串为数组
- 注意:
- Bash 字符串索引从 0 开始,但
${str:start} 的 start 从 0 开始
- 避免在
[ ] 中使用 ==(推荐用 [[ ]])