正则表达式与文本三剑客grep、sed、awk
目录
一、正则表达式
1.1、字符匹配
1.2、次数匹配
1.3、位置锚定
1.4、分组或其他
二、扩展正则表达式
三、grep
四、awk
4.1、常用命令选项
4.2、工作原理
4.3、基础用法
4.4、内置变量
4.5、模式
4.6、条件判断
4.7、awk中的循环语句
4.8、数组
4.9、脚本
五、sed
5.1、sed脚本格式
5.2、sed命令
5.3、搜索替换
5.4、分组后向引用
一、正则表达式
正则表达式,又称规则表达式。(英语:Regular Expression),在代码中常简写为 regex、regexp 或 RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
正则表达式不只有一种,而且linux中不同的程序可能会使用不同的正则表达式,如:grep sed awk egrep
LINUX 中常用的有两种正则表达式引擎:
- 基础正则表达式:BRE
- 扩展正则表达式: ERE
通配符与正则表达式的区别:
- 通配符一般用于文件名匹配
- 正则表达式一般用于匹配文件内容
1.1、字符匹配
元字符 | 定义 |
. | 匹配除换行符\n之外的任意单个字符 |
[ ] | 匹配中括号内任意单个字符 |
[^ ] | 匹配除中括号内任意单个字符 |
[:alnum:] | 数字和字母 |
[:alpha:] | 任意大小写英文字符 |
[:lower:] | 小写字母 |
[:upper:] | 大写字母 |
[:blank:] | 空白字符(空格和制表符) |
[:space:] | 空格、制表符、换行符、回车符等空白 |
[:cntrl:] | 不可打印的控制字符(退格、删除、警铃等) |
[:digit:] | 十进制数字 |
[:xdigit:] | 十六进制数字 |
[:graph:] | 可打印的非空白字符 |
[:print:] | 可打印字符 |
[:punct:] | 标点符号 |
\w | 匹配单词 |
\W | |
\s | |
\S |
1.2、次数匹配
元字符 | 定义 |
* | 匹配前面字符人任意次,包括0次 |
.* | 任意长度的任意字符,不包括0次 |
\? | 匹配前面字符出现0次或1次 |
\+ | 前面字符出现最少1次 |
\{n\} | 匹配前面字符n次 |
\{m,n\} | 匹配前面字符最少m次,最多n次 |
\{,n\} | 匹配前面字符最多n次,≤n |
\{n,\} | 匹配前面字符最少n次 |
1.3、位置锚定
元字符 | 定义 |
^ | 行首锚定,用于模式最左侧 |
$ | 行尾锚定,用于模式最右侧 |
^PATTTERN$ | 匹配整行 |
^$ | 空行,不包括空格行 |
^[:space:]*$ | 空白行 |
\b,\< | 词首锚定,用于模式最左侧 |
\b,\> | 词尾锚定,用于模式最右侧 |
1.4、分组或其他
元字符 | 定义 |
( ) | 分组,将多个字符作为一个整体 |
(x\|y) | 由左向右匹配指定字符 |
二、扩展正则表达式
通常情况下会使用基础正则表达式就已经足够了,但有时为了简化整个指令,需要使用 范围更广的扩展正则表达式。
#次数匹配
* #前面任意字符
? #0或1次
+ #1次以上
{n} #匹配n次
{m,n} #最少m次,最多n次
{,n} #前面字符最多n次,≤n
{n,} #前面字符最少n次
#分组匹配
() #多个字符当作整体处理
\1,\2,... #向后引用
| #或
三、grep
语法格式:grep 参数 文件名
常用参数:
-m<x> | 找到x行后停止查找 |
-v | 取反 |
-i | 忽略大小写 |
-n | 显示行号 |
-c | 统计行数 |
-o | 仅显示匹配到的字符 |
-q | 静默模式,不输出任何信息 |
-A<x> | 显示匹配行,及之后的x行 |
-B | 显示匹配行,及之前的x行 |
-C | 显示匹配行,及前后x行 |
-e | 多个选项间的逻辑或 |
-E | 使用扩展正则表达式 |
-w | 只显示全字符合的列 |
-F | 不使用正则表达式 |
-f | 处理两个文件相同内容,以第一个文件为匹配条件 |
-r | 递归目录,不处理软链接 |
-R | 递归目录,处理软连接 |
--color=auto | 高亮匹配字符 |
参考示例
#输出除之外的所有行 -v 选项
grep -v "match_pattern" file_name#标记匹配颜色 --color=auto 选项
grep "match_pattern" file_name --color=auto#使用正则表达式 -E 选项:
grep -E "[1-9]+"
egrep "[1-9]+"#选项 -e 制动多个匹配样式:
echo this is a text line | grep -e "is" -e "line" -o
is
is
line#在多级目录中对文本进行递归搜索:
grep "text" . -r -n
# .表示当前目录。#忽略匹配样式中的字符大小写:
echo "hello world" | grep -i "HELLO"
# hello
四、awk
awk命令来自三位创始人Alfred Aho、Peter Weinberger、Brian Kernighan的姓氏缩写,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。
它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
语法格式:awk [选项] -f '脚本'/脚本文件 '模式{处理动作}'
4.1、常用命令选项
- -F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:,默认的分隔符是连续的空格或制表符
- -v var=value 赋值一个用户定义变量,将外部变量传递给awk
- -f scripfile 从脚本文件中读取awk命令
- -m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
4.2、工作原理
- 第一步:执行 BEGIN {commands} 语句块中的语句;
- 第二步:从文件或标准输入(stdin)读取一行,然后执行 pattern {commands} 语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
- 第三步:当读至输入流末尾时,执行 END {commands} 语句块。
BEGIN语句块:在awk开始从输入流中读取行 之前 被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块:在awk从输入流中读取完所有的行 之后 即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
pattern语句块:中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{print},即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
4.3、基础用法
awk '模式{处理动作}'
#BGEIN{}模式
[root@localhost ~]# awk '{print}'
1
1
aabb
aabb
^C
[root@localhost ~]# awk '{print "aabb"}'
1
aabb#提取磁盘的分区利用率
[root@localhost ~]# df |awk '{print $5}'
已用%
0%
0%
2%
0%
80%
19%
1%
80%
0%#提取用户名和uid号
[root@localhost ~]# cat /etc/passwd |awk -F: '{print $1,$3}'
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
..............#提取ip地址
[root@localhost ~]# ifconfig ens33 |awk 'NR==2{print $2}'
192.168.153.23
4.4、内置变量
变量 | 定义 |
FS | 字段分隔符(默认空格) |
OFS | 输出字段分隔符(默认空格) |
NF | 字段数,执行过程中对应当前字段数 |
NR | 记录数,执行过程中对应当前行号 |
$0 | 当前处理的行的整行内容 |
$n | 当前处理行的第n个字段/列 |
FILENAME | 当前输入的文件名 |
RS | 记录分隔符(默认一个换行符) |
参考示例
#FS变量的使用,-F优先级高于FS变量
[root@localhost ~]# awk -v "FS=:" '{print $1FS$3}' /etc/passwd
root:0
bin:1
daemon:2
[root@localhost ~]# awk -F: '{print $1":"$3}' /etc/passwd
root:0
bin:1
daemon:2#OFS变量的使用,替换分隔符
[root@localhost ~]# cat /etc/passwd|awk -v "OFS=--" -F: '{print $1,$3}'|head -n3
root--0
bin--1
daemon--2
[root@localhost ~]# cat /etc/passwd|awk -v "OFS=--" -v "FS=:" '{print $1,$3}'|head -n3
root--0
bin--1
daemon--2#RS变量的使用,替换分隔符为换行符
[root@localhost ~]# echo $PATH|awk -v "RS=:" '{print}'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin#NF变量的使用,显示最后一列
[root@localhost ~]# df |awk '{print $NF}'
挂载点
/dev
/dev/shm
/run
/sys/fs/cgroup
/
/boot
/run/user/42
/var/lib/docker/overlay2/b3191762ed94dc8a583e6da75d8db197b583d63c7f925833df49e5b51e865a4f/merged
/run/user/0
[root@localhost ~]# df |awk '{print $(NF-1)}'
已用%
0%
0%
2%
0%
80%
19%
1%
80%
0%#NR变量的使用,匹配对应行
[root@localhost ~]# cat /etc/passwd |head -n3|awk '{print NR,$0}'
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
[root@localhost ~]# cat /etc/passwd|awk 'NR==1,NR==3{print NR,$0}'
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
[root@localhost ~]# cat /etc/passwd|head -n8|awk '(NR%2)==0{print NR,$0}'
2 bin:x:1:1:bin:/bin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
8 halt:x:7:0:halt:/sbin:/sbin/halt
4.5、模式
awk [选项] '模式{处理动作}'
#/正则表达式/:使用通配符的扩展集。
#匹配从root开头,ftp结尾的行
[root@localhost ~]# awk -F: '/^root/,/^ftp/{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
#仅匹配root开头,ftp开头的行
[root@localhost ~]# awk -F: '/^root/||/^ftp/{print $1,$3}' /etc/passwd
root 0
ftp 14
#关系表达式,使用运算符进行操作,可以是字符串或数字的比较测试
#n++表示不匹配第一行,即NR!=1
[root@localhost ~]# ss -natp|awk 'n++{print $1}'|sort|uniq -c1 ESTAB12 LISTEN
[root@localhost ~]# ss -natp|awk 'n++{a[$1]++}END{for(i in a){print a[i],i}}'
12 LISTEN
1 ESTAB[root@localhost ~]# seq 4|awk 'i=!i'
1
3
[root@localhost ~]# seq 4|awk '!(i=!i)'
2
4
[root@localhost ~]# seq 4|awk -v i=1 'i=!i'
2
4
4.6、条件判断
awk 选项 '模式 {条件|执行动作}'
#过滤用户名及uid
[root@localhost ~]# cat /etc/passwd|awk -F: '{if($3>1000)print $1,$3}'
nfsnobody 65534
[root@localhost ~]# cat /etc/passwd|awk -F: '$3>1000{print $1,$3}'
nfsnobody 65534
[root@localhost ~]# cat /etc/passwd|awk -F: '{if($3>=uid){uid=$3;user=$1;sh=$NF}}END{print user,uid,sh}'
nfsnobody 65534 /sbin/nologin
4.7、awk中的循环语句
#for循环
#for(变量;条件;表达式){语句}
[root@localhost ~]# awk 'BEGIN{total=0;for(i=0;i<=100;i++){total+=i;}print total;}'
5050
4.8、数组
数组是awk的灵魂,处理文本中最不能少的就是它的数组处理。因为数组索引(下标)可以是数字和字符串在awk中数组叫做关联数组(associative arrays)。awk 中的数组不必提前声明,也不必声明大小。数组元素用0或空字符串来初始化,这根据上下文而定。
#得到数组长度
#length返回字符串以及数组长度,split进行分割字符串为数组,也会返回分割得到数组长度
[root@localhost ~]# awk 'BEGIN{info="it is a test";lens=split(info,tA," ");print length(tA),lens;}'
4 4#输出数组内容
#无序输出
[root@localhost ~]# awk 'BEGIN{info="it is a test";split(info,tA," ");for(k in tA){print k,tA[k];}}'
4 test
1 it
2 is
3 a
#有序输出
[root@localhost ~]# awk 'BEGIN{info="it is a test";tlen=split(info,tA," ");for(k=1;k<=tlen;k++){print k,tA[k];}}'
1 it
2 is
3 a
4 test
4.9、脚本
-f scripfile 从脚本文件中读取awk命令
[root@localhost opt]# vim asdf.txt
{if($3>=1000)print $1,$3}
[root@localhost opt]# awk -F: -f asdf.txt /etc/passwd
nfsnobody 65534
123123 1000
五、sed
stream editor的缩写,其功能是利用语法/脚本对文本文件进行批量的编辑操作。
它是文本处理中非常重要的工具,能够完美的配合正则表达式使用,功能不同凡响。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。
接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有 改变,除非你使用重定向存储输出。
Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
语法格式:sed [选项] '命令' 文件名
常用参数:
-n | 就显示脚本处理后的结果 |
-e | 使用指定脚本处理输入的文本文件 |
-f | 使用指定脚本文件处理输入的文本文件 |
-r/-E | 支持扩展正则表达式 |
-i.bak | 直接修改文件内容而不输出到终端,并备份文件 |
[root@localhost opt]# sed -n -e '/^r/p' -e'/^b/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin[root@localhost opt]# sed -i.bak '1,4d' aaa #删除第1,第4行
[root@localhost opt]# cat aaa
eeeee
fffff
ggggg
hhhhh
[root@localhost opt]# cat aaa.bak
aaaaa
bbbbb
ccccc
ddddd
eeeee
fffff
ggggg
hhhhh
5.1、sed脚本格式
#范围匹配
[root@localhost opt]# seq 5|sed -n 'p' #不指定范围则打印全文
1
2
3
4
5
[root@localhost opt]# seq 5|sed -n '3p' #打印第3行
3
[root@localhost opt]# seq 5|sed -n '1,3p' #打印第1,第3行
1
2
3
[root@localhost opt]# seq 5|sed -n '1,+2p' #打印第1行及后2行
1
2
3
[root@localhost opt]# seq 5|sed -n '1,2!p' #取反
3
4
5
#步进
#打印第一行起,后每步进2打印一行,即奇数行
[root@localhost opt]# seq 10|sed -n '1~2p'
1
3
5
7
9
#打印第二行起,后每步进2打印一行,即偶数行
[root@localhost opt]# seq 10|sed -n '2~2p'
2
4
6
8
10
#第二行起,每三行步进打印
[root@localhost opt]# seq 10|sed -n '2~3p'
2
5
8
#第三行起,每三行步进打印
[root@localhost opt]# seq 10|sed -n '3~3p'
3
6
9
5.2、sed命令
p | 打印模板块的行 |
q | 退出Sed |
s | 替换指定字符 |
d | 删除,删除选择的行 |
a | 在当前行下面插入文本 |
i | 在指定行上面插入文本 |
c | 把选定的行改为新的文本 |
y | 把一个字符翻译为另外的字符 |
= | 打印当前行号 |
r | 从file中读行 |
w | 写并追加模板块到file末尾 |
! | 取反 |
#打印到第三行退出
[root@localhost ~]# cat /etc/passwd|sed '3q'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin#指定行后插入
[root@localhost ~]# seq 5|sed '2alook'
1
2
look
3
4
5
[root@localhost ~]# seq 5|sed '4alook\n eyes'
1
2
3
4
lookeyes
5
[root@localhost ~]# seq 5|sed '4alook\neyes'
1
2
3
4
look
eyes
5
[root@localhost ~]# seq 5|sed '3a look'
1
2
3
look
4
5
[root@localhost ~]# seq 5|sed '3a\ look'
1
2
3look
4
5#指定行前插入
[root@localhost ~]# seq 5|sed '3i\ look'
1
2look
3
4
5
[root@localhost ~]# seq 5|sed '4ilook\neyes'
1
2
3
look
eyes
4
5#替换行
[root@localhost ~]# seq 5|sed '3c\ look'
1
2look
4
5
[root@localhost ~]# seq 5|sed '4clook\neyes'
1
2
3
look
eyes
5
5.3、搜索替换
替换标记 | 定义 |
g | 行内全面替换 |
p | 打印行 |
w | 把行写入一个文件 |
x | 互换模板块中的文本和缓冲区中的文本 |
y | 把一个字符翻译为另外的字符 |
\1 | 子串匹配标记 |
& | 已匹配字符串标记 |
基本格式 s/pattern/string/修饰符
#替换第二个.为@
[root@localhost opt]# sed 's/\./@/2' /etc/hosts
127.0@0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6@localdomain6#匹配字符后添加
[root@localhost opt]# sed -n 's/r..t/&er/gp' /etc/passwd
rooter:x:0:0:rooter:/rooter:/bin/bash
operator:x:11:0:operator:/rooter:/sbin/nologin
ftp:x:14:50:FTP User:/var/fterp:/sbin/nologin
5.4、分组后向引用
#提取ip地址
[root@localhost opt]# ifconfig ens33|sed -rn '2s/.*inet ([0-9.]+) .*/\1/p'
192.168.153.23#提取文件权限
[root@localhost opt]# stat aaa文件:"aaa"大小:24 块:8 IO 块:4096 普通文件
设备:fd00h/64768d Inode:18799731 硬链接:1
权限:(0644/-rw-r--r--) Uid:( 0/ root) Gid:( 0/ root)
环境:unconfined_u:object_r:usr_t:s0
最近访问:2025-05-02 21:53:35.697373969 +0800
最近更改:2025-05-02 21:53:24.391268086 +0800
最近改动:2025-05-02 21:53:24.391268086 +0800
创建时间:-
[root@localhost opt]# stat aaa |sed -nr '4s/.*([0-9]{4}).*/\1/p'
0644
[root@localhost opt]# stat aaa|sed -n '4p'|egrep -o "[0-9]{4}"
0644
[root@localhost opt]# stat aaa|awk -F"[(/]" 'NR==4{print $2}'
0644