引言

Shell 脚本语言包含了众多用于解决 Linux 系统问题的工具,其中有不少和文本处理相关,包括 sed、awk和grep等,这些工具可以互相结合以满足文本处理的需求。


一、正则表达式

1. 正则表达式概述

  • 通常用于判断语句中,用来检查某一字符串是否满足某一格式

  • 正则表达式是由普通字符与元字符组成

  • 普通字符包括大小写字母、数字、标点符号及一些其他符号

  • 元字符是指在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式

  • Linux 中常用的有两种正则表达式引擎
    ①基础正则表达式:BRE
    ②扩展正则表达式:ERE

文本处理工具基础正则表达式扩展正则表达式
vi 编辑器支持\
grep支持\
egrep支持支持
sed支持\
awk支持支持

2. 基础正则表达式

  • 基础正则表达式是常用的正则表达式部分,常用的元字符及作用如下表所示:
元字符作用
\转义字符,用于取消特殊符号的含义,如:\!,\n
^匹配字符串开始的位置,如:^world 匹配以 world 开头的行
$匹配字符串结束的位置,如: world$ 匹配以 world 结尾的行
.匹配除 \n(换行)之外的任意的1个字符
*匹配前面子表达式0次或者多次
[list]匹配 list 列表中的一个字符,如:[0-9] 匹配任意一位数字
[^list]匹配任意不在 list 列表中的1个字符,如: [^0-9]匹配任意一位非数字字符
\ {n \ }匹配前面的子表达式n次,如:[0-9]{2\ }匹配两位数字
\ {n,\ }匹配前面的子表达式不少于n次,如:[0-9]\ {2,\ }表示两位及两位以上数字
\ {n,m\ }匹配前面的子表达式n到m次,如: [a-z]\ {2,3\ }匹配两到三位的小写字母
  • 注意 egrep, awk使用{n}、{n,}、{n,m}匹配时“{}"前不用加“\”

  • 示例

[root@localhost /home]#grep -n "^the" test.txt           #筛选以 the 开头的行
4:the tongue is boneless but it breaks bones.12!

[root@localhost /home]#grep -n "words$" test.txt         #筛选以 words 结尾的行
9:Actions speak louder than words

[root@localhost /home]#grep 'sh[io]rt' test.txt          #筛选包含字符串shirt或者short的行
he was short and fat.
He was wearing a blue polo shirt with black pants.

[root@localhost /home]#grep '[0-9]' test.txt             #筛选出包含数字0~9的行
the tongue is boneless but it breaks bones.12!
PI=3.141592653589793238462643383249901429

[root@localhost /home]#grep '[a-c]' test.txt             #筛选出包含字母a到c的行,不包含大写
he was short and fat.
He was wearing a blue polo shirt with black pants.

[root@localhost /home]#grep -i '[a-c]' test.txt          #grep -i 选项忽略大小写
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
Actions speak louder than words
#AxyzxyzxyzxyzC

[root@localhost /home]#grep -n '[^a-z]oo' test.txt       #筛选oo前面不是小写字母的行
3:The home of Football on BBC Sport online.
[root@localhost /home]#grep -n '^[a-z]oo' test.txt       #筛选oo前面是小写字母的行
5:google is the best tools for search keyword.


[root@localhost /home]#grep -n 'o\{2\}' test.txt         #查找字母o 出现二次及以上的行
3:The home of Football on BBC Sport online.
5:google is the best tools for search keyword.
8:a wood cross!
12:#woood #
13:#woooooood
15:I bet this place is really spooky late at night!

[root@localhost /home]#grep -n 'wo\{2,5\}d' test.txt     #查找以w开头,以d结尾的2~5个o的行
8:a wood cross!
12:#woood #

[root@localhost /home]#grep -n 'wo\{2,\}d' test.txt      #查找以w开头,d结尾2个或以上的o的行
8:a wood cross!
12:#woood #
13:#woooooood

[root@localhost /home]#grep o* test.txt                 #匹配所有内容,包括空白行
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.
The year ahead will test our political establishment to the limit.

[root@localhost /home]#grep -n 'oo*' test.txt          #匹配至少含有一个o的行
                                                #第一个o必须存在,第二个o可以出现0次或多次
1:he was short and fat.
2:He was wearing a blue polo shirt with black pants.
3:The home of Football on BBC Sport online.
4:the tongue is boneless but it breaks bones.12!
5:google is the best tools for search keyword.
6:The year ahead will test our political establishment to the limit.

3. 扩展正则表达式

  • 扩展正则表达式是对基础正则表达式的扩充和深化

  • 支持的工具有 egerp 和 awk

  • 扩展正则表达式元字符

元字符作用
+匹配前面子表达式1次以上,如:go+d,将匹配至少一个 o
?匹配前面子表达式0次或者1次,如: go?d,将匹配 gd 或 god
()将括号中的字符串作为一个整体,如:g(oo) +d,将匹配。整体1次以上,如good,gooood等
I以或的方式匹配字条串,如:good I great ,将匹配 good 或者 great
  • 示例
[root@localhost /home]#egrep -n 't(a|e)st' test.txt        #匹配包含tast或者test的行
6:The year ahead will test our political establishment to the limit.
17:tast
         
[root@localhost /home]#egrep 'A(xyz)+C' test.txt           #匹配A开头C结尾中间是xyz字符串的行
#AxyzxyzxyzxyzC

[root@localhost /home]#egrep 'wo+d' test.txt               #匹配至少包含一个o的行
a wood cross!
#woood #
#woooooood

二、Sed 工具

1. Sed 概述

  • sed 是一个文本处理器,它依赖于正则表达式,可以读取文本内容,根据指定条件对数据进行添加、删除、替换等操作,被广泛应用于 shell 脚本,以完成自动化处理任务。

  • sed 在处理数据时默认不直接修改源文件,而是把当前处理的行存储在临时缓冲区中,所有指令都在缓冲区中操作,处理完成后把缓冲区内容默认输出到屏幕,接着处理下一行内容,这样不断地重复,直到文件末尾,文件的本身内容没有改变(除非是用重定向存储输出)

2. Sed 基本语法

  • sed 命令格式
sed [选项] '操作' 参数
sed [选项] -f 脚本 参数
  • 常见的 sed 命令选项
选项说明
-e或–expression=表示用指定命令或脚本来处理输入的文本文件
-f或–file表示用指定的脚本文件来处理输入的文本文件
-h或–help显示帮助
-i直接编辑文本文件
-n、–quiet或silent表示仅显示处理后的结果
  • “操作” 用于指定对文件操作的动作行为,也就是 sed 的命令。通常情况下是采用的 “[n1[,n2]]” 操作参数的格式。n1、n2 是可选的,代表选择进行操作的行数,如操作需要在 5~ 20 行之间进行,则表示为“5,20 动作行为”。常见的操作包括以下几种。
选项说明
a增加,在当前行下面增加一行指定内容。
c替换,将选定行替换为指定内容
d删除,删除选定的行
i插入,在选定行上面插入一行指定内容
p打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。其通常与“-n”选项一起使用
s替换,替换指定字符
y字符转换

3. 用法示例

  • 输出所有内容
[root@localhost /home]#sed -n 'p' test.txt 
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
......
#等同于用 cat 查看
[root@localhost /home]#cat test.txt 
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
......
  • 输出n行的内容
[root@localhost /home]#sed -n '3p' test.txt      #输出第三行的内容
The home of Football on BBC Sport online.
[root@localhost /home]#sed -n '3,5p' test.txt    #输出三到五行的内容
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.
  • 输出奇、偶数行内容

在这里插入图片描述
在这里插入图片描述

[root@localhost /home]#sed -n '1,5{p;n}' test.txt    #输出1~5行的奇数行内容
he was short and fat.
The home of Football on BBC Sport online.
google is the best tools for search keyword.

在这里插入图片描述

  • 输出包含某些需要查找的内容的行
[root@localhost /home]#sed -n '4,/the/p' test.txt         #输出第四行开始第一个包含the的行
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.

[root@localhost /home]#sed -n '/the/=' test.txt           #输出包含 the 的行的行号
4
5
6
  • 删除
[root@localhost /home]#nl test.txt                   #nl表示命令行用于计算文件的行数
     1	he was short and fat.
     2	He was wearing a blue polo shirt with black pants.
     3	The home of Football on BBC Sport online.
     4	the tongue is boneless but it breaks bones.12!
     5	google is the best tools for search keyword.
......
       
[root@localhost /home]#nl test.txt |sed '4d'         #删除第四行
     1	he was short and fat.
     2	He was wearing a blue polo shirt with black pants.
     3	The home of Football on BBC Sport online.
     5	google is the best tools for search keyword.
...... 

[root@localhost /home]#nl test.txt |sed '4,7d'       #删除4-71	he was short and fat.
     2	He was wearing a blue polo shirt with black pants.
     3	The home of Football on BBC Sport online.
     8	a wood cross!
......

[root@localhost /home]#sed '/^[a-z]/d' test.txt     #删除以a到z开头的行
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
The year ahead will test our political establishment to the limit.
PI=3.141592653589793238462643383249901429
......

[root@localhost /home]#sed '/^$/d' test.txt         #删除空行

  • 替换
[root@localhost /home]#sed 's/the/THE/' test.txt     #把小写的the全部转换成大写的THE
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
THE tongue is boneless but it breaks bones.12!

[root@localhost /home]#sed 's/the/THE/g' test.txt    #把所有行中的the替换成THE

[root@localhost /home]#sed 's/o//g' test.txt         #把所有行中的o替换为空
he was shrt and fat.
He was wearing a blue pl shirt with black pants.

[root@localhost /home]#sed 's/^/#/' test.txt         #在每一行的开头插入#号
#he was short and fat.
#He was wearing a blue polo shirt with black pants.
#The home of Football on BBC Sport online.
#the tongue is boneless but it breaks bones.12!

[root@localhost /home]#sed '/the/s/^/#/' test.txt    #每一行the的前面加#
#the tongue is boneless but it breaks bones.12!
#The year ahead will test our political establishment to the limit.

[root@localhost /home]#sed '3,5s/the/THE/g' test.txt  #35行的the替换成THE
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
THE tongue is boneless but it breaks bones.12!
google is THE best tools for search keyword.

[root@localhost /home]#sed '/the/s/o/O/g' test.txt    #把有the的行里面的小写o替换成大写O
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
the tOngue is bOneless but it breaks bOnes.12!

  • 迁移符合条件的文本
    常用参数如下:
参数说明
H复制到剪贴板
g、G将剪贴板中的数据覆盖、追加至指定行
w保存为文件
r读取指定文件
a追加指定内容
[root@localhost /home]#sed '/the/{H;d};$G' test.txt     #将所有包含the的行剪切到末尾行
he was short and fat.
a wood cross!

the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.
The year ahead will test our political establishment to the limit.

[root@localhost /home]#sed '1,5{H;d};17G' test.txt      #把15行剪切到末尾行

[root@localhost /home]#sed '/the/w out.file' test.txt   #将所有包含the的行保存到另一个文件中
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!
......

[root@localhost /home]#cat out.file 
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.
The year ahead will test our political establishment to the limit.

[root@localhost /home]#sed '/the/r /etc/hostname' test.txt 
the tongue is boneless but it breaks bones.12!
localhost.localdomain
google is the best tools for search keyword.
localhost.localdomain
The year ahead will test our political establishment to the limit.
localhost.localdomain
PI=3.141592653589793238462643383249901429
a wood cross!

[root@localhost /home]#hostname            #把etc下hostname里面的内容放到test.txt中the的行下
localhost.localdomain

[root@localhost /home]#sed '3aNEW' test.txt        
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
NEW

[root@localhost /home]#sed '3aNEW1\nNEW2\nNEW3' test.txt    #在第三行插入多行内容
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
NEW1
NEW2
NEW3

  • 调用脚本
[root@localhost /home]#sed '1,5{H;d};18G' test.txt 
I bet this place is really spooky late at night!
Misfortunes never come alone/single.
tast


he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.


[root@localhost /home]#vim open.list

1,5H
1,5d
18G

[root@localhost /home]#sed -f open.list test.txt 
I bet this place is really spooky late at night!
Misfortunes never come alone/single.
tast


he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.

三、awk 工具

1. awk 概述

  • Awk 是一种处理文本文件的语言,是一个强大的文本分析工具

  • 它是专门为文本处理设计的编程语言,也是行处理软件,通常用于扫描、过滤、统计汇总工作
    数据可以来自标准输入也可以是管道或文件

2. 工作原理

  • 逐行读取文本,默认以空格或 tab 键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。

  • sed 命令常用于一整行的处理,而 awk 比较倾向于将一行分成多个"字段"然后再进行处理。

  • awk 信息的读入也是逐行读取的,执行结果可以通过 print 的功能将字段数据打印显示。

  • 在使用 awk 命令的过程中,可以使用逻辑操作符" &“表示"与”、"||表示"或"、"!“表示非”,还可以进行简单的数学运算,如 +、一、*、/、%、^ 分别表示加、减、乘、除、取余和乘方。

3. Awk 基本语法

awk [选项] '模式或条件{编辑指令}' 文件1 文件2

awk -f脚本文件 文件1 文件2
  • 在 Awk 语句中,模式部分决定何时对数据进行操作,若省略则后续动作时刻保持执行状态,模式可以为条件语句、符合语句或正则表达式等。

  • 每条编辑指令可以包含多条语句,多条语句之间要使用分号或者空格分隔的多个 { } 区域

  • 常用选项-F定义字段分隔符,默认以空格或者制表符作为分隔符

  • Awk 常见的内置变量如下

变量描述
FS指定每行文本的字段分隔符,默认为空格或制表位
NF当前处理的行的字段个数
NR当前处理的行的行号(序数)
$0当前处理的行的整行内容
$n当前处理行的第n个字段(第n列)
FILENAME被处理的文件名
RS数据记录分隔,默认为 \n ,即每行为一条记录

4. Awk 用法示例

  • 打印文本内容
[root@localhost /home]#awk '/^the/{print}' test.txt      #输出以the开头的行
the tongue is boneless but it breaks bones.12!

[root@localhost /home]#awk '/night!$/{print}' test.txt   #输出以night!为结尾的行
I bet this place is really spooky late at night!

[root@localhost /home]#awk -F ':' '/bash$/{print|"wc -l"}' /etc/passwd
5                                                          #统计可登录系统用户的个数

[root@localhost /home]#awk 'NR==1,NR==4{print}' test.txt   #输出第1行到第4行内容
he was short and fat.
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!

[root@localhost /home]#awk 'NR==1||NR==4{print}' test.txt  
he was short and fat.                                       #输出第14行内容
the tongue is boneless but it breaks bones.12!

[root@localhost /home]#awk '(NR>=1)&&(NR<=4){print}' test.txt 
he was short and fat.                                      #输出第1行到第4行内容
He was wearing a blue polo shirt with black pants.
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!

[root@localhost /home]#awk '(NR%2)==1{print}' test.txt     #输出所有奇数行的内容

[root@localhost /home]#awk '(NR%2)==0{print}' test.txt     #输出所有偶数行的内容

[root@localhost /etc]#awk -F : '!($3<900)' /etc/passwd     #输出第3个字段不小于900的行
polkitd:x:999:997:User for polkitd:/:/sbin/nologin         #“!”表示取反
libstoragemgmt:x:998:995:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin
......

#使用awk过程的时候可以使用条件表达式,条件表达式的运算涉及两个符号,冒号和问号
#其实质就是 if...else语句的捷径,有着和if...else相同的结果。
[root@localhost /etc]#awk -F : '{if($3>200) {print $0}}' /etc/passwd
polkitd:x:999:997:User for polkitd:/:/sbin/nologin         #输出第3个字段大于200的行
libstoragemgmt:x:998:995:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin

[root@localhost /etc]#awk -F : '{max=($3 > $4) ? $3:$4;print max}' /etc/passwd
0  
1
2
4
7
#如果第3个字段的值大于第4个字段的值,则把问号前表达式的值赋予给max,否则就将冒号后的值赋予给max

[root@localhost /etc]#awk -F : '{max=($3 > 200) ? $3:$1;print max}' /etc/passwd
root
bin
daemon
adm
#如果第3个字段的值大于200,则把第3个字段的值赋给max,否则就将第1个字段的值赋给max
.......
  • 按字段输出文本
#输出处理数据的行号,每处理完一条记录,NR值加1
[root@localhost /etc]#awk -F : '{print NR,$0}' /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
......

#输出第3列小于5的第1列和第3列数据
[root@localhost /etc]#awk -F ":" '$3 < 5 {print $1 $3 }' /etc/passwd
root0
bin1
daemon2
adm3
lp4

#输出包含7个字段,并且第一个字段中包含 root 的行的第1与第2个字段的内容
[root@localhost /etc]#awk -F ":" '($1~"root")&&(NF==7){print$1,$3}' /etc/passwd
root 0

#输出第3行到第7行中以冒号为分隔符的第1列与第7列的数据
[root@localhost /etc]#awk -F ":" 'NR==3,NR==7 {print $1,$7 }' /etc/passwd
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown

#输出以冒号为分隔符的第1列和第3列数据
[root@localhost /etc]#awk -F ":" '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2

或者

[root@localhost /etc]#awk 'BEGIN {FS=":"}{print$1,$3}' /etc/passwd
root 0
bin 1
daemon 2

#统计以/bin/bash 为结尾的行数
root@localhost /etc]#awk 'BEGIN{x=0};/\/bin\/bash$/ {x++};END{print x}' /etc/passwd
2

#$0显示整行的内容
[root@localhost /etc]#awk 'BEGIN{x=0};/\/bin\/bash$/{x++;{print x,$0}};END {print x}' /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 gulei:x:1000:1000:GuLei:/home/gulei:/bin/bash

  • Awk 执行的顺序:
    ① 首先执行BEGIN{ }中的操作
    ② 然后从指定的文件中逐行读取数据,自动更新NF、NR、$0、$1等内建变量的值,去执行‘模式或条件{编辑指令}’
    ③ 最后执行 END{ }中的后续操作

  • Awk 也可以利用管道符号来处理命令的结果

[root@localhost /etc]#date |awk '{print "Month: "$2 "\nYear: ",$6}'
Month: 09月
Year:  CST

总结

  • Sed 与 Awk 是依赖于正则表达式的优秀的文本处理工具,可以对指定的文本数据进行特定操作

  • Awk 适合对文本进行抽取处理,Sed 更加适合对文本进行编辑操作

Logo

更多推荐