Skip to content

字符串

字符串定义

单引号

bash
# 单引号:原样输出,不解析变量和转义字符
message='Hello World'
message='Hello $name'      # 输出:Hello $name
message='Hello\nWorld'     # 输出:Hello\nWorld
message='It\'s me'         # 错误:不能在单引号中使用单引号

双引号

bash
# 双引号:解析变量和转义字符
name="张三"
message="Hello $name"      # 输出:Hello 张三
message="Hello\nWorld"     # 输出:Hello(换行)World
message="It's me"          # 正确:可以使用单引号

不加引号

bash
# 不加引号:解析变量和通配符
name="张三"
message=Hello$name         # 输出:Hello张三
message=Hello $name        # 输出:Hello 张三
message=*.txt              # 会展开匹配的文件

字符串拼接

直接拼接

bash
# 直接拼接
name="张三"
message="Hello, " $name "!"  # 错误:不能这样拼接

# 正确方式
message="Hello, $name!"       # 输出:Hello, 张三!

使用引号拼接

bash
# 使用引号
name="张三"
greeting="Hello, "
message="$greeting$name!"     # 输出:Hello, 张三!

使用花括号

bash
# 使用花括号
name="张三"
message="${name}你好"         # 输出:张三你好

字符串长度

获取长度

bash
# 获取字符串长度
name="张三"
echo ${#name}                 # 输出:2

# 获取数组长度
arr=("a" "b" "c")
echo ${#arr[@]}               # 输出:3

实用示例

bash
# 检查字符串是否为空
name=""
if [ ${#name} -eq 0 ]; then
    echo "字符串为空"
fi

# 限制字符串长度
name="这是一个很长的字符串"
if [ ${#name} -gt 10 ]; then
    echo "字符串过长"
fi

字符串提取

基本语法

bash
${变量名:起始位置:长度}

提取示例

bash
name="Hello World"

# 从位置 0 开始,提取 5 个字符
echo ${name:0:5}              # 输出:Hello

# 从位置 6 开始到结尾
echo ${name:6}                # 输出:World

# 提取最后 3 个字符
echo ${name: -3}              # 输出:rld

# 提取倒数第 5 个字符开始的 3 个字符
echo ${name: -5:3}            # 输出:Wor

实用示例

bash
# 获取文件扩展名
filename="document.txt"
extension=${filename##*.}
echo $extension               # 输出:txt

# 获取文件名(不含扩展名)
basename=${filename%.*}
echo $basename               # 输出:document

字符串替换

替换第一个匹配

bash
name="Hello World"

# 替换第一个 World 为 Bash
echo ${name/World/Bash}       # 输出:Hello Bash

# 替换第一个 l 为 L
echo ${name/l/L}              # 输出:HeLlo World

替换所有匹配

bash
name="Hello World"

# 替换所有 l 为 L
echo ${name//l/L}             # 输出:HeLLo WorLd

# 替换所有空格为下划线
echo ${name// /_}             # 输出:Hello_World

删除匹配

bash
name="Hello World"

# 删除第一个匹配
echo ${name/World/}            # 输出:Hello

# 删除所有匹配
echo ${name//o/}              # 输出:Hell Wrld

开头和结尾

bash
name="prefix_Hello_suffix"

# 删除开头最短匹配
echo ${name#prefix_}          # 输出:Hello_suffix

# 删除开头最长匹配
echo ${name##*_}              # 输出:suffix

# 删除结尾最短匹配
echo ${name%_suffix}          # 输出:prefix_Hello

# 删除结尾最长匹配
echo ${name%%_*}              # 输出:prefix

字符串查找

查找子串

bash
name="Hello World"

# 查找子串位置(使用 expr)
expr index "$name" "World"    # 输出:7

# 检查是否包含子串
if [[ "$name" == *"World"* ]]; then
    echo "包含 World"
fi

检查开头和结尾

bash
name="Hello World"

# 检查开头
if [[ "$name" == "Hello"* ]]; then
    echo "以 Hello 开头"
fi

# 检查结尾
if [[ "$name" == *"World" ]]; then
    echo "以 World 结尾"
fi

字符串转换

大小写转换(Bash 4+)

bash
name="Hello World"

# 转换为大写
echo ${name^^}                # 输出:HELLO WORLD

# 转换为小写
echo ${name,,}                # 输出:hello world

# 首字母大写
echo ${name^}                 # 输出:Hello world

# 首字母小写
echo ${name,}                 # 输出:hello World

使用 tr 命令

bash
name="Hello World"

# 转换为大写
echo "$name" | tr '[:lower:]' '[:upper:]'  # 输出:HELLO WORLD

# 转换为小写
echo "$name" | tr '[:upper:]' '[:lower:]'  # 输出:hello world

# 删除所有数字
echo "abc123" | tr -d '0-9'  # 输出:abc

字符串分割

使用 IFS

bash
# 设置分隔符
IFS=',' read -r -a array <<< "apple,banana,orange"

# 遍历数组
for fruit in "${array[@]}"; do
    echo "$fruit"
done

使用 cut 命令

bash
text="apple,banana,orange"

# 按逗号分割,提取第一个字段
echo "$text" | cut -d',' -f1  # 输出:apple

# 按逗号分割,提取第二个字段
echo "$text" | cut -d',' -f2  # 输出:banana

使用 read 命令

bash
text="apple banana orange"

# 按空格分割
read -r -a array <<< "$text"

# 遍历数组
for item in "${array[@]}"; do
    echo "$item"
done

字符串比较

相等比较

bash
str1="hello"
str2="hello"

# 使用 =
if [ "$str1" = "$str2" ]; then
    echo "相等"
fi

# 使用 ==
if [[ "$str1" == "$str2" ]]; then
    echo "相等"
fi

不等比较

bash
str1="hello"
str2="world"

# 使用 !=
if [ "$str1" != "$str2" ]; then
    echo "不相等"
fi

大小比较

bash
str1="apple"
str2="banana"

# 字典序比较
if [[ "$str1" < "$str2" ]]; then
    echo "$str1 小于 $str2"
fi

if [[ "$str1" > "$str2" ]]; then
    echo "$str1 大于 $str2"
fi

长度比较

bash
str1="hello"
str2="hello world"

# 比较长度
if [ ${#str1} -lt ${#str2} ]; then
    echo "$str1$str2 短"
fi

字符串处理实用函数

去除空格

bash
# 去除前后空格
trim() {
    local var="$*"
    var="${var#"${var%%[![:space:]]*}"}"
    var="${var%"${var##*[![:space:]]}"}"
    echo -n "$var"
}

# 使用
text="  hello world  "
trimmed=$(trim "$text")
echo "$trimmed"  # 输出:hello world

检查是否为数字

bash
is_number() {
    local num="$1"
    [[ "$num" =~ ^-?[0-9]+$ ]]
}

# 使用
if is_number "123"; then
    echo "是数字"
fi

检查是否为邮箱

bash
is_email() {
    local email="$1"
    [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]
}

# 使用
if is_email "test@example.com"; then
    echo "是邮箱"
fi

实用示例

示例1:生成随机字符串

bash
#!/bin/bash

# 生成随机字符串
generate_random_string() {
    local length=$1
    local random_string=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $length | head -n 1)
    echo "$random_string"
}

# 使用
random_string=$(generate_random_string 10)
echo "随机字符串: $random_string"

示例2:字符串格式化

bash
#!/bin/bash

# 格式化字符串
format_string() {
    local template="$1"
    shift
    printf "$template\n" "$@"
}

# 使用
format_string "姓名: %s, 年龄: %d" "张三" 25

示例3:字符串统计

bash
#!/bin/bash

text="Hello World Hello"

# 统计单词数
word_count=$(echo "$text" | wc -w)
echo "单词数: $word_count"

# 统计字符数
char_count=${#text}
echo "字符数: $char_count"

# 统计特定单词出现次数
hello_count=$(echo "$text" | grep -o "Hello" | wc -l)
echo "Hello 出现次数: $hello_count"

最佳实践

1. 始终使用引号

bash
# 好的做法
echo "$name"

# 不好的做法
echo $name

2. 使用花括号

bash
# 好的做法
echo "${name}你好"

# 不好的做法
echo $name你好

3. 检查变量是否为空

bash
# 好的做法
if [ -n "$name" ]; then
    echo "$name"
fi

# 不好的做法
echo $name

总结

字符串操作的关键点:

  1. 定义字符串:单引号、双引号、不加引号
  2. 字符串拼接:直接拼接或使用引号
  3. 获取长度:${#变量名}
  4. 提取子串:${变量名:起始位置:长度}
  5. 字符串替换:${变量名/模式/替换}${变量名//模式/替换}
  6. 大小写转换:${变量名^^}(大写)或 ${变量名,,}(小写)
  7. 字符串比较:=, !=, <, >

下一节我们将学习数组的操作。