目录
引用文章:
Bash 基础知识系列 #6:处理字符串操作 | Linux 中国
菜鸟教程
前言:
shell 脚本是一种非常实用的技能,而其中最为实用的不是各种 shell 命令,而是关于字符串处理的部分。
一、Bash 的字符串操作
- 获取字符串长度
格式:${#string}
$ str1=aaaaa
$ echo {#str1}
结果> 5
$ str2="bbb"
$ echo {#str2}
结果> 3
- 连接字符串
格式:str3=$str1$str2
$ str1="hello"
$ str2="world"
$ show=$str1$str2
$ echo "show: $show"
结果> show: helloworld
- 提取子字符串
格式:${string:$pos:$len}
pos从 0 开始
$ str=nihao
$ substr=${str:2:2}
$ echo $substr
结果> ha
- 替换 Bash 中的子字符串
格式:
替换第一次出现的子字符串:${string/substr1/substr2}
替换所有出现的地方:${string//substr1/substr2}
$ statement="the bash is good shell"
$ statement=${statement/good/best}
$ echo $statement
结果> the bash is best shell
- 删除子字符串
格式:
仅删除第一次出现的子字符串:${string/substring}
删除所有出现的内容:${string//substr}
$ string="itsfoss is awesome"
$ echo ${string/its}
结果> foss is awesome
- 截取子字符串
格式:
${parameter#word} # 删除匹配前缀 去掉左边,最短匹配模式
${parameter##word} ##最长匹配模式
${parameter%word} # 删除匹配后缀
${parameter%%word} # % 去掉右边,最短匹配模式,%%最长匹配模式
$ URL="http://www.baidu.com/baike/user.html"
$ echo ${URL#*//}
结果> www.baidu.com/baike/user.html
$ echo ${URL%%//*}
结果> http:
二、正则表达式
2.1 模式
- 字面值字符:可以直接匹配它们自身。例如:字母、数字、空格等。
- 特殊字符:具有特殊的含义和功能。例如:“.”、“*”、“+”、“?” 等。
- 字符类:用于匹配方括号内的任意一个字符。用 [ ] 包围的字符集合
- 元字符:用于匹配特定类型的字符。例如:\d、\w、\s等,对应 数字、字母、空白字符等
- 量词:用于指定匹配的次数或范围。例如:{n}、{n, }、{n, m} 等。
- 边界符号:用于匹配字符串的开头、结尾 或 单词边界位置。例如:“^”、“$”、“\b”、“\B” 等。
2.2 语法
正则表达式可以在文本中查找、替换、提取 和 验证 特定的模式。
2.2.1 普通字符
[ABC]、[^ABC](除 ABC 之外的字符)、[A-Z]、.(相当于[^\n\r])、
[\s\S](\s 是匹配所有空白符,包括换行,\S 是非空白符,不包括换行)、
\w(匹配 字母、数字、下划线)、\d(匹配任意一个阿拉伯数字)。
2.2.2 非打印字符
\cx(x是字母,\cM 匹配 Ctrl-M 或 回车)
剩下的都是转义字符,基于C语言理解即可。
2.2.3 特殊字符
特别字符 | 描述 |
---|---|
$ | 匹配输入字符串的结尾位置。如果要匹配 $ 字符本身,使用 $。 |
() | 标记一个子表达式的 开始 和 结束 位置。 |
* | 匹配前面的子表达式 零次 或 多次。要匹配 * 字符,请使用 \* |
+ | 匹配前面的子表达式 一次 或 多次。要匹配 + 字符,请使用 \+ |
. | 匹配除换行符 \n 之外的任何单字符。要匹配 .,请使用 \. |
[ | 标记一个中括号表达式的开始。要匹配[,请使用 \[ |
? | 匹配前面的子表达式 零次 或 一次,或 指明 一个 非贪婪限定符。 要匹配 ? 字符,请使用 \? |
\ | 将下一个字符标记为 或 特殊字符、或原义字符、或向后引用、或八进制引用。 |
^ | 匹配输入字符串的开始位置,除非在方括号表达式中使用。 |
{ | 标记限定符表达式的开始。要匹配 { 字符,请使用 \{ |
| | 指明两项之间的一个选择。要匹配 |,轻松使用 | |
2.2.4 限定符
字符 | 描述 |
---|---|
* | 匹配前面的子表达式 零次 或 多次。 |
+ | 匹配前面的子表达式 一次 或 多次。 |
? | 匹配前面的子表达式零次或一次。 |
{n} | n为非负整数。指定字符匹配 n 次。 |
{n, } | n是一个非负整数,指定字符至少匹配 n 次。 |
{n, m} | m 和 n 均为 非负整数,n <= m。最少匹配 n 次,且最多匹配 m 次。 |
- 和 + 限定符 都是 贪婪的,因为它们会尽可能多的匹配文字,只有在它们后面加上一个 ? 就可以实现 非贪婪 或 最小匹配。
非贪婪 —— 用 ?,只匹配一次。
2.2.5 定位符
字符 | 描述 |
---|---|
^ | 匹配输入字符串 开始 的位置。 |
$ | 匹配输入字符串 结尾 的位置。 |
\b | 匹配一个单词的 前 或 后 边界,即 字 与 空格间 的位置。 |
\B | 非单词边界匹配。 |
2.2.6 选择
用 () 将所有选择项括起来,相邻的选项之间用 | 分隔。
() 表示捕获分组,它会把每个分组里匹配的值保存起来(放在临时缓冲区),多个匹配值可以通过数字 n 来查看,表示第 n 个捕获组的内容。
副作用:相关的匹配会被缓存,此时可用 ?: 放在第一个选项前面 来消除这种副作用。
可以用 非捕获元字符 ?:、?=、?! 来重写捕获,忽略对相关匹配的保存。
关于临时缓冲区:
所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的 顺序 存储。
缓冲区编号从 1 开始,最多可存储 99 个捕获的 子表达式。
每个缓冲区可以使用 \n 来访问,n 为缓冲区的编号。
2.2.7 非捕获元(先行断言 和 后行断言)
?:
是 非捕获元 之一,还有两个非捕获元 是 ?=
和 ?!
,它俩还有更多含义:
?=
是 正向预查,在任何开始 匹配 () 的正则表达式模式的位置来 匹配 搜索字符串
?!
是 反向预查,在任何开始 不匹配 () 的正则表达式模式的位置来 匹配 搜索字符串。
非捕获元 | 格式 | 功能 |
---|---|---|
?= | exp1(?=exp2) | 【正向先行断言】查找 exp2 前面的 exp1 |
?<= | (?<=exp2)exp1 | 【正向后行断言】查找 exp2 后面的 exp1 |
?! | exp1(?!exp2) | 【负向先行断言】查找后面不是 exp2 的 exp1 |
?<! | (?<!exp2)exp1 | 【负向后行断言】查找前面是不是 exp2 的 exp1 |
2.2.8 反向引用
反向引用就是在 正则表达式 之后用 \n 访问 第 n 个临时缓冲区。如 2.2.6 所述,最大访问缓存区编号为 99。
反向引用 最简单、最有用 的应用之一是提供查找文本中两个相同的相邻单词的匹配项的能力。
2.3 修饰符(标记)
修饰符用于指定额外的匹配策略,位于表达式 之外,格式为 /pattern/flags
修饰符 | 含义 | 描述 |
---|---|---|
i | ignore - 不区分大小写 | 将匹配设置为不区分大小写 |
g | global - 全局匹配 | 查找所有的匹配项 |
m | multi line - 多行匹配 | 使边界字符 ^ 和 $ 匹配每一行的 开头 和 结尾 |
s | 修饰 .,使其包含 \n | 默认情况下 “.” 是匹配除 \n 之外的任何字符 |
2.4 元字符
元字符就是之前讲的各种特殊符号和转移符号。
2.5 运算符优先级
顺序:从左到右,遵循优先级顺序
下表从高到低说明了各种运算符的优先级:
运算符 | 描述 |
---|---|
|转义符 | |
(),(?😃,(?=),[] | 圆括号 和 方括号 |
*,+,?,{n},{n,},{n,m} | 限定符 |
^,$,\ 任何元字符、 任何字符 | 定位点 和 序列(即:位置和顺序) |
| | 替换,“或”操作 字符具有高于替换运算符的优先级,使得 |
2.6 匹配规则
2.6.1 基本模式匹配
模式可以很简单,由普通的字符串组成,也可以非常复杂,用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。
2.6.2 字符簇
字符簇 就是 一种更自由的描述我们要的模式的方法。
如何支持多次匹配呢?
这时候就要用到 {} 来确定前面内容的重复次数了。
{x} —— 前面的 字符 或 字符簇 只出现 x 次
{x,} —— 前面的 内容 出现 x 或 更多次的次数
{x,y} —— 前面的 内容 至少出现 x 次,但不超过 y 次
三、相关命令
3.1 cut
- 功能
1、显示文件的内容,将其内容输出到 stdout 上
2、合并两个或多个文件的内容【Eg:cut f1 f2 > f3
】 - 字符串处理特征
cut 可以支持按指定的字符划分字符串的功能。【按列处理】
-b:以字节为单位进行分割
-c:以字符为单位进行分隔【也可以指定一个范围,如:6-9】
-d:指定字段的 分隔符,默认的字段分隔符为 “tab”
-f:与 -d 合用,指定显示的区域(列号,提取第几列)
3.2 grep
- 功能:用于查找指定文件里符合条件的 字符串,显示其所在的整行的字符。
-i:忽略大小写匹配
-n:显示匹配行的行号
-r:递归查找 子目录 中的文件
-c:纸打印匹配的行数
-A <显示行数>:除了显示符合条件的哪一行外,还显示其后的几行
3.3 sed
- 功能:利用脚本来处理、编辑文本文件
-e <script>:以选项中指定的 script 来处理输入的文本文件
【表示多点编辑,即 同时操作多条 sed 的<script>】
-f <script文件>:以选项中指定的 script文件 来处理输入的文本文件
-n:仅显示 script 处理后的结果
== <script>格式 ================================================
a:新增。a后面的字符串会在下一行出现
c:取代。c后面的字符串可以取代 n1,n2 之间的行
d:删除。d后通常不接任何东西
i:插入。i后面的字符串会在上一行出现
p:打印。通常 p 会与 -n 一起运行
s:取代。可直接进行取代的工作,通常搭配 正则表达式
q:退出。
注意:
1、sed 后面的动作,务必以 ‘…’ 括住。
2、数据的搜寻并执行命令$ nl testfile | sed -n '/oo/{s/oo/kk/;p;q}' 5 Gkkgle
这里把 oo 替换为 kk,再输出,最后的 q 是退出。
3.4 awk
awk是一种处理文本文件的语言,是一个强大的文本分析工具
- 语法:
awk [选项参数] ‘script’ var=value file(s)
或
awk [选项参数] -f scriptfile var=value file(s) - 参数:
-F:指定输入文件分隔符,一个字符,或 一个正则表达式。后面直接跟特定的符号即可。
【多个分隔符,'[分隔符1分隔符2……]'】
-v:创建一个用户定义变量,并赋值
【Eg:awk -va=1 '{printf $1,$1+a}' log.txt】
-f:从脚本文件中读取 awk 命令
============= log.txt =============
2 this is a test
3 Do you like awk
This's a test
10 There are orange,apple,mongo
===================================
swk '{[pattern] action}' {filenames} # 行匹配语句 awk ' ' 只能用单引号
# 1、每行按 空格 或 TAB 分隔,可指定项
$ awk '{print $1, $4}' log.txt
# 2、格式化输出
$ awk '{printf "%-8s %-10s\n",$1,$4}' log.txt
- 运算符
运算符 | 描述 |
---|---|
=,+=,-=,/=,%=,^=,**= | 赋值 |
?: | C条件表达式 |
|| | 逻辑或 |
&& | 逻辑或 |
~,!~ | 匹配 正则表达式 和 不匹配 正则表达式 |
<,<=,>,>=,!=,== | 关系运算符 |
空格 | 连接 |
+,- | 加,减 |
*,/,% | 乘,除 与 求余 |
+,-,! | 一元 加,减 的 逻辑非 |
^*** | 求幂 |
++,– | 增加 或 减少,作为 前缀 或 后缀 |
$ | 字段引用 |
in | 数组成员 |
# 过滤 第一列 > 2 并且 第二列 = ‘Are’ 的行。
$ awk '$1>2 && $2=="Are" {print $1,$3}' log.txt
- 内建变量(可以做出来按列输出的效果)
变量 | 描述 |
---|---|
$n | 当前记录的第 n 个字段,字段间由 FS 分隔 |
$0 | 完整的输入记录 |
ARGC | 命令行参数的数目 |
ARGIND | 命令行中当前文件的位置(从0开始算) |
ARGV | 包含命令行参数的数组 |
FILENAME | 当前文件名 |
FNR | 各文件分别计数的行号 |
IGNORECASE | 如果为真,忽略大小写匹配 |
NF | 一条记录的字段的数目 |
NR | 所读文件内容的行号,从1开始 |
- 正则
~ 表示模式开始。/ / 中间的是 “模式”(可以直接是要匹配的内容,匹配的是行)
! 表示模式取反。 - awk 脚本
注意两个关键词 BEGIN 和 END
BEGIN{ 这里面是 执行前 的语句 }
END{ 这里面是 处理完所有的行后要执行的语句 }
{ 这里面是处理每一行时要执行的语句 }
awk脚本的文件名:xxx.awk
#!/bin/awk -f
#运行前
BEGIN {
math = 0
english = 0
computer = 0
printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
printf "---------------------------------------------\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
printf "---------------------------------------------\n"
printf " TOTAL:%10d %8d %8d \n", math, english, computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}
执行:awk -f xxx.awk yyy.txt
补充一个内容:grep、sed、awk 是Linux操作文本的三大利器,三者合称 文本三剑客。
四、查找
4.1 find
- 按文件名查找:
find 路径 -name ”文件名“
- 按文件类型查找:·find 路径 -type 类型·
类型:
f —— 普通文件
d —— 目录
l —— 符号链接
b —— 块设备文件
c —— 字符设备文件
s —— 套接字文件
p —— 管道文件