字符串长度、截取理论和操作

Shell字符串操作符详解

一、操作符速查表

操作符名称作用示例结果
${#var}字符串长度返回字符串长度str="hello"; echo ${#str}5
${var:m}从m截取到结尾从第m个字符开始str="hello"; echo ${str:2}llo
${var:m:len}从m截取len长度从m开始取len个str="hello"; echo ${str:1:3}ell
${var#pattern}删最短前缀删除开头匹配的最短部分file="a.b.c"; echo ${file#*.}b.c
${var##pattern}删最长前缀删除开头匹配的最长部分file="a.b.c"; echo ${file##*.}c
${var%pattern}删最短后缀删除结尾匹配的最短部分file="a.b.c"; echo ${file%.*}a.b
${var%%pattern}删最长后缀删除结尾匹配的最长部分file="a.b.c"; echo ${file%%.*}a

二、详细示例

2.1 ${#var} – 字符串长度


str="Hello World"
echo "长度: ${#str}"           # 输出: 11


name="张三"
echo "姓名长度: ${#name}"      # 输出: 2(中文字符算1个)

# 数组长度
arr=("a" "b" "c")
echo "数组长度: ${#arr[@]}"    # 输出: 3
echo "第一个元素长度: ${#arr[0]}" # 输出: 1

2.2 ${var:m} – 从位置m到结尾


str="Hello World"
echo "${str:6}"                # 输出: World(从第6个字符开始)

# 支持负数(从后往前)
echo "${str: -5}"              # 输出: World(最后5个字符)
# 注意:-5前面要有空格,或者用括号
echo "${str: -5}"              # World
echo "${str:(-5)}"             # World

# 实际应用:获取文件扩展名
filename="document.pdf"
echo "${filename: -4}"         # 输出: .pdf(但可能不准确)

2.3 ${var:m:len} – 从m开始取len长度

#!/bin/bash
str="Hello World"
echo "${str:0:5}"              # 输出: Hello
echo "${str:6:3}"              # 输出: Wor

# 提取日期
date="2000-12-20"
year="${date:0:4}"
month="${date:5:2}"
day="${date:8:2}"
echo "年: $year, 月: $month, 日: $day"
# 输出: 年: 2000, 月: 12, 日: 20

2.4 ${var#pattern} – 删除最短前缀


# # 从开头删除,最短匹配
filename="/usr/local/bin/script.sh"
echo "${filename#*/}"          # 输出: usr/local/bin/script.sh(删除第一个/)
echo "${filename#/*/}"         # 输出: local/bin/script.sh(删除/usr/)

# 提取文件名(删除路径)
fullpath="/home/user/docs/file.txt"
echo "${fullpath##*/}"         # 用##提取文件名(最长匹配)
# 输出: file.txt

2.5 ${var##pattern} – 删除最长前缀

# ## 从开头删除,最长匹配
filename="/usr/local/bin/script.sh"
echo "${filename##*/}"         # 输出: script.sh(删除所有路径)

# 提取协议
url="https://example.com/page"
echo "${url##*://}"            # 输出: example.com/page

2.6 ${var%pattern} – 删除最短后缀

# % 从结尾删除,最短匹配
filename="document.pdf"
echo "${filename%.*}"          # 输出: document(删除最短后缀)

# 多级扩展名
file="archive.tar.gz"
echo "${file%.*}"              # 输出: archive.tar(删除.gz)

2.7 ${var%%pattern} – 删除最长后缀

# %% 从结尾删除,最长匹配
file="archive.tar.gz"
echo "${file%%.*}"             # 输出: archive(删除所有扩展名)

# 获取目录名
path="/home/user/docs/file.txt"
echo "${path%%/*}"             # 输出: (空) 因为第一个字符就是/
echo "${path#/}%%/*"           # 需要组合使用

三、实际应用场景

3.1 文件路径处理

#!/bin/bash
# file_ops.sh

file="/home/user/docs/report-2024.pdf"

# 提取文件名(去掉路径)
filename="${file##*/}"
echo "文件名: $filename"       # report-2024.pdf

# 提取目录(去掉文件名)
dirname="${file%/*}"
echo "目录: $dirname"          # /home/user/docs

# 提取文件名(去掉扩展名)
basename="${filename%.*}"
echo "基础名: $basename"       # report-2024

# 提取扩展名
extension="${filename##*.}"
echo "扩展名: $extension"      # pdf

# 提取年份
year="${basename##*-}"
echo "年份: $year"             # 2024

3.2 URL处理

#!/bin/bash
url="https://example.com:8080/path/to/page?name=test"

# 提取协议
protocol="${url%%://*}"
echo "协议: $protocol"         # https

# 提取域名和端口(去掉协议)
without_proto="${url#*://}"
domain_port="${without_proto%%/*}"
echo "域名+端口: $domain_port"  # example.com:8080

# 提取域名(去掉端口)
domain="${domain_port%:*}"
echo "域名: $domain"           # example.com

# 提取端口
port="${domain_port#*:}"
echo "端口: $port"             # 8080

# 提取路径
path="${without_proto#*/}"
path="${path%%\?*}"
echo "路径: $path"             # path/to/page

# 提取查询参数
query="${url#*\?}"
echo "查询: $query"            # name=test

3.3 版本号处理

#!/bin/bash
version="1.2.3-beta"

# 提取主版本
major="${version%%.*}"
echo "主版本: $major"          # 1

# 提取次版本
minor="${version#*.}"
minor="${minor%%.*}"
echo "次版本: $minor"          # 2

# 提取修订号
patch="${version##*.}"
patch="${patch%%-*}"
echo "修订号: $patch"          # 3

# 提取预发布标签
tag="${version#*-}"
echo "标签: $tag"              # beta

四、组合使用

#!/bin/bash
# 复杂字符串处理

str="Hello-World-2024.txt"

# 1. 获取第一个单词
first="${str%%-*}"
echo "第一个: $first"          # Hello

# 2. 获取最后一个部分
last="${str##*-}"
echo "最后一个: $last"         # 2024.txt

# 3. 获取中间部分
middle="${str#*-}"
middle="${middle%-*}"
echo "中间: $middle"           # World

# 4. 多步处理
echo "原始: $str"
echo "长度: ${#str}"
echo "前5字符: ${str:0:5}"
echo "后3字符: ${str: -3}"
echo "去掉后缀: ${str%.*}"
echo "去掉前缀: ${str#*-}"

五、总结

操作符方向匹配策略记忆口诀
${#var}长度# 像数字符号
${var#pattern}开头最短一个#最小
${var##pattern}开头最长两个#最大
${var%pattern}结尾最短一个%最小
${var%%pattern}结尾最长两个%最大

规则很简单

  • # 从开头删,% 从结尾删
  • 一个符号 删最短,两个符号 删最长

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注