目录
基础正则表达式
正则表达式的定义
正则表达式又称正规表达式、常规表达式。在代码中常简写为 regex、regexp 或 RE。正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,简单来说,是一种匹配字符串的方法,通过一些特殊符号,实现快速查找、删除、替换某个特定字符串。
正则表达式是由普通字符与元字符组成的文字模式。模式用于描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。其中普通字符包括大小写字母、数字、标点符号及一些其他符号,元字符则是指那些在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。
正则表达式一般用于脚本编程与文本编辑器中。很多文本处理器与程序设计语言均支持正则表达式,例如 Linux 系统中常见的文本处理器(grep、egrep、sed、awk)以及应用比较广泛的 Python 语言。正则表达式具备很强大的文本匹配功能,能够在文本海洋中快速高效地处理文本。
语法如下:
\ 转义字符,取消特殊符号的含义
^ 匹配字符串的开始位置,如:^word匹配以word开头的行
$ 匹配字符串的结束位置,如:word$匹配以word结尾的行
. 匹配除 \n (换行)之外的任意一个字符
* 匹配前面的子表达式0次或者多次
[list] 匹配list列表中的一个字符,如:[0-9] 匹配任一位数字
[^list] 匹配不在list列表中的一个字符,如:[^0-9] 匹配任意一位非数字字符
\{n\} 匹配前面的子表达式n次,如:[0-9]\{2\} 匹配两位数字
\{n,\} 匹配前面的字表达式不少于n次,如:[0-9]\{2,\} 表示两位及两位以上数字
\{n,m\} 匹配前面的字表达式n到m次,如:[a-z]\{2,3\} 匹配两到三位的小写字母
如下以grep命令实例:
grep root /etc/passwd //筛选文件中包含root的行
grep ^root /etc/passwd //筛选以root开头的行
grep bash$ /etc/passwd //筛选以bash结尾的行
grep -v root /etc/passwd //筛选文中不包含root的行
grep 'r..d' /etc/passwd //筛选出r 和d 之间有两个字符的行
grep '[^s]bin' /etc/passwd //筛选bin前面不是s的行
grep '^$' /etc/passwd //筛选出空白行
grep 't[es]' /etc/passwd //筛选包含字符串te或ts的行
grep '0\{1,\}' /etc/passwd //筛选数字0出现1次或1次以上的行
grep -e 'ntp' -e 'root' /etc/passwd // -e参数查找多个模式
grep [0-3] /etc/passwd //筛选包含数字0-3的行
grep '[^a-z]ae' /etc/passwd //筛选ae前面不是小写字母的行
grep '^[a-z]ae' /etc/passwd //筛选ae前面是小写字母的行
grep 'the' 1.txt //过滤出包含 the 的行
grep -n 'the' 1.txt //过滤出包含 the 的行,显示行号
grep -ni 'the' 1.txt //过滤出包含 the 的行,显示行号,不区分大小写
grep -vn 'the' 1.txt //过滤出不包含 the 的行,显示行号
grep -n 'sh[io]rt' 1.txt //过滤出包含 shirt 和short的行
grep -n 'oo' 1.txt //过滤出包含oo的行
grep -n '[w]oo' 1.txt //过滤出oo前面是 w的行
grep -n '[^w]oo' 1.txt //过滤出oo前面不是 w 的行
grep -n '[^a-z]oo' 1.txt //过滤出oo前面不是小写字母的行
grep -n '[0-9]' 1.txt //过滤出包含任意一位数字的行
grep -n '^the' 1.txt //以the开头的行
grep -n '[a-z]' 1.txt //过滤出包含任意一位小写字母的行
grep -n '[^a-z]' 1.txt //过滤出任意一位不是小写字母的行
grep -n '^[a-z]' 1.txt //过滤出以小写字母开头的行
grep -n '^[A-Z]' 1.txt //过滤出以大写字母开头的行
grep -n '[a-zA-Z]' 1.txt //过滤出包含任意一位字母的行
grep -n '[^a-zA-Z]' 1.txt //过滤出任意一位不是字母的行
grep -n [^a-zA-Z] 1.txt //过滤出任意一位不是字母的行
grep -n '^[^a-zA-Z]' 1.txt //过滤出开头不是字母的行
grep -n '[\.$]' 1.txt //过滤出以 . 结尾的行
grep -n '^$' 1.txt //过滤出空行
grep -n 'w..d' 1.txt //过滤出w和d中间有两位字符
grep -n 'ooo*' 1.txt //过滤出2个以上的o的行
grep -n 'woo*d' 1.txt //过滤出w和d中间有1个以上的o
grep -n 'w.*d' 1.txt //过滤出w和d中间有0个以上的字符
grep -n '[0-9][0-9]' 1.txt //过滤出任意2位数字的行
grep -n '[0-9][0-9]*' 1.txt //过滤出任意1位以上的数字
grep -n 'o\{2\}' 1.txt //过滤出包含2个o的行
grep -n 'wo\{2,5\}d' 1.txt //过滤出w和d中间有2-5个o
grep -n 'wo\{2,\}d' 1.txt //过滤出w和d中间有2个以上的o
元字符总结
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符 |
^ | 匹配输入字符串的开始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的子表达式要次或多次 |
+ | 匹配前面的子表达式一次或多次 |
? | 匹配前面的子表达式零次或一次 |
. | 匹配除换行符(\n、w)之外的任何单个字符 |
[a-z] | 字符范围。匹配指定范围内的任意字符。 |
{n} | n 是一个非负整数,匹配确定的n次 |
{n,} | n是一个非负整数,至少匹配n 次 |
{n,m} | m 和n均为非负整数,其中n<= m。最少匹配n次且最多匹配 m 次 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于[^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\fn\r\t\v]。 |
\S | 匹配任何非空白字符。等价于[^ \fn\nt\v]。 |
\w | 匹配字母、数字、下划线。等价于'[A-Za-z0-9_]' |
\W | 匹配非字母、数字、下划线。等价于'[^A-Za-z0-9_]'. |
\n | 匹配一个换行符 |
\f | 匹配一个换页符 |
\r | 匹配一个回车符 |
扩展正则表达式
+ | 匹配前面的子表达式1次以上,如:go+d,将匹配至少一个o |
? | 匹配前面的字表达式0次或者1次,如:go?d,将匹配gd或god |
() | 将 () 号中的字符串作为一个整体,如:(xyz)+,将匹配xyz整体1次以上 |
| | 以或的方式匹配字符串,如:good|great,将匹配good或者great |
()+ | 辨别多个重复的组,如:egrep -n 'A(xyz)+C' test.txt,将查询开头的“A”结尾是“C”,中间有一个以上的“xyz”字符串的意思 |
以egrep为例:
egrep 0+ /etc/passwd //匹配至少包含一个0的行
egrep '(root|ntp)' /etc/passwd //匹配包含root或ntp的行
egrep ro?t /etc/passwd //匹配rt或者rot的行
egrep -v '^$|^#' /etc/passwd //过滤文件中的空白行与#开头的行
sed 工具使用方法
sed(stream Epitor)是一个强大而简单的文本解析转换工具,可以读取文本,并根据指定的条件对文本内容进行编辑(删除、替换、添加、移动等),最后输出所有行或者仅输出处理的某些行。sed 也可以在无交互的情况下实现相当复杂的文本处理操作,被广泛应用于 Shel1 脚本中,用以完成各种自动化处理任务。
sed 的工作流程主要包括读取、执行和显示三个过程。
- 读取:sed从输入流(文件、管道、标准输入)中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)
- 执行:默认情况下,所有的sed 命令都在模式空间中顺序地执行,除非指定了行的地址,否则sed 命令将会所有的行上依次执行。
- 显示:发送修改后的内容到输出流,在发送数据后,模式空间将会被清空。
sed基本语法
sed [选项] '操作' 参数
sed [选项] -f scriptfile 参数
例如:
sed -e ‘编辑指令’ 文件1 文件2 ……
sed -n ‘编辑指令’ 文件1 文件2 ……
sed -i ‘编辑指令’ 文件1 文件2 ……
常用的sed 命令选项主要包含以下几种:
- -e 或--expression=:表示用指定命令或者脚本来处理输入的文本文件。
- -f或--file=:表示用指定的脚本文件来处理输入的文本文件。
- -h或--help:显示帮助。
- -n、--quiet 或 silent:表示仅显示处理后的结果。
- -i:直接编辑文本文件。
“操作”用于指定对文件操作的动作行为,也就是 sed 的命令。通常情况下是采用的“[n1[,n2]]”操作参数的格式。n1、n2 是可选的,代表选择进行操作的行数,如操作需要在 5~20 行之间进行,则表示为“5,28 动作行为”。常见的操作包括以下几种。
- a:增加,在当前行下面增加一行指定内容。
- c:替换,将选定行替换为指定内容。
- d:删除,删除选定的行。
- i:插入,在选定行上面插入一行指定内容。
- p:打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。其通常与“-n”选项一起使用。
- s:替换,替换指定字符。
- y:字符转换。
- r:读取指定文件
- w:保存为文件
以sed 为例:
sed -n 'p' /etc/passwd //将所有内容输出
sed -n '6p' /etc/passwd //将第6行内容输出
sed -n '6,8p' /etc/passwd //将第6~8行内容输出
sed -n 'p;n' /etc/passwd //将所有奇数行输出
sed -n 'n;p' /etc/passwd //将所有偶数行输出
sed -n '1,10{p;n}' /etc/passwd //将1~10行中的奇数行输出
sed -n '1,10{n;p}' /etc/passwd //将1~10行中的偶数行输出
sed -n '10,${n;p}' /etc/passwd //将10~末尾之间的奇数行输出
p;n:从第1行开始是奇数,从第2行开始是偶数
n;p:从第1行开始是偶数,从第2行开始是奇数
sed -n '/root/p' /etc/passwd //将匹配包含root的行进行输出
sed -n '10,/mon/p' /etc/passwd //将从第10行至第一个包含mon的行进行输出,如果没有mon,则从第十行输出到最后一行
sed -nr '/ro{1,}t/p' /etc/passwd //匹配不少于1次前导字符o,
加 –r 参数支持拓展正则表达式
sed -n '/root\|ntp/p' /etc/passwd //输出包含root或者ntp的行
sed -n '/mon/=' /etc/passwd //将包含mon所在的行的行号输出
“=”号用来输出行号
插入:
sed -e '5q' /etc/passwd //输出前5行信息后退出,q退出
sed '/root/i aaaaaaa' /etc/passwd //在含有root行的前一行添加aaaaaaa
sed '/root/a aaaaa' /etc/passwd //在含有root行的后一行添加aaaaa
sed '3a ADMIN' /etc/passwd //在第3行后面插入一行ADMIN
删除:
sed '1d' /etc/passwd //删除第1行
sed '$d' /etc/passwd //删除最后1行
sed '/^$/d' etc/passwd //删除空行
sed '2,4d' /etc/passwd //删除第2~4行
sed '/root/d' /etc/passwd //删除含有root的行
sed '/root/!d' /etc/passwd //删除不包含root的行,!:表示取反
sed '/^root/d' /etc/passwd //删除以root开头的行
sed '/nologin$/d' /etc/passwd //删除以nologin结尾的行
替换:
sed 's/root//g' /etc/passwd //将文件中所有的root都删除
sed '/root/c aaaaa' /etc/passwd //将含有root的行替换为aaaaa
sed -n 's/root/admin/2p' /etc/passwd //将每行的第二个root替换成admin
sed '/root/s/root/ROOT/g' /etc/passwd //将包含root行的所有行中的root替换为ROOT
sed '1,3s/bin/BIN/g' /etc/passwd //将第1~3行中的所有bin都替换为BIN
sed 's/^/#/' /etc/passwd //在每行行首插入 # 号
sed 's/$/ABC/' /etc/passwd //在每行行尾插入字符 ABC
sed '/root/s/^/#/' /etc/passwd //将包含root的行的行首插入 # 号
sed '1c ABC' /etc/passwd //将第一行替换为 ABC
sed 'y/rot/ROT/' /etc/passwd //将rot替换为ROT
// y表示应替换
sed '1,10y/root/ROOT/' /etc/passwd //将第1~10行中的root对应替换为ROOT
迁移: h:表示保存当前模式到一个缓冲区
G:将剪贴板中的数据追加至指定行
H:复制到剪贴板
g:将剪贴板中的数据覆盖到指定行
w:保存为文件
sed '/root/w file1' /etc/passwd //将对应root行另存为文件file1
sed '/root/{H;d};$G' /etc/passwd //将包含root的行迁移到末尾
sed '1,5{H;d};$G' /etc/passwd //将第1~5行内容迁移到末尾
执行多次命令:
Sed -ne 's/root/admin/' -ne 's/bash/sh/p' /etc/passwd
//将root和bash行作替换
-e可以将多个命令连接起来,也可将多个编辑命令保存到文件中,通过-f指定文件,来完成多个处理操作
直接修改文件内容:
sed -i 's/^/#/' /etc/passwd //在每行开头插入 # 号,直接修改原文件
sed -i 's/^#//g' /etc/passwd //将每行开头的 # 号删除,直接修改原文件
awk 工具使用方法
awk逐行读取文本,默认以空格为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,对比该行是否与给定的模式相匹配,并按模式或者条件执行编辑命令,也可以从脚本中调用编辑指令过滤出相应内容。
awk有两种语法格式
awk 【选项】 ‘模式或条件 {编辑指令}’ 文件1 文件2
awk -f 脚本文件 文件1 文件2
awk 包含几个特殊的内建变量(可直接使用)如下:
FS | 指定每行文本的字段分隔符,默认为空格或制表位。 |
NF | 当前处理的行的字段个数。 |
NR | 当前处理的行的行号(序数)。 |
$0 | 当前处理的行的整行内容。 |
$n | 当前处理行的第n个字段(第n列)。 |
FILENAME | 被处理的文件名。 |
RS | 数据记录分隔,默认为\n,即每行为一条记录, |
例如:awk
awk '/^root/ {print}' /etc/passwd //输出以root开头的行
awk '/nologin$/ {print}' /etc/passwd //输出以nologin结尾的行
awk -F ":" '/bash$/ {print |"wc -l"}' /etc/passwd //统计可登录系统用户的个数
awk:可以使用关系运算符作为“条件”,用于比较数字与字符串,只有条件为真,才执行指定的动作。
> |
< |
>= |
<= |
== |
!= |
&& |
|| |
! |
+ |
- |
* |
/ |
% |
^ |
大于 |
小于 |
大于等于 |
小于等于 |
等于 |
不等于 |
与 |
或 |
非 |
加 |
减 |
乘 |
除 |
取余 |
乘方 |
例如:
awk 'NR==1,NR==3 {print}' /etc/passwd //输出第1行至第3行内容
awk 'NR==1||NR==3 {print}' /etc/passwd //输出第1,3行内容
awk 'NR==1,NR==3 {print}' /etc/passwd //输出第1行至第3行内容
awk '(NR%2)==1 {print}' /etc/passwd //输出所有奇数行的内容
awk '(NR%2)==0 {print}' /etc/passwd //输出所有偶数行的内容
awk -F : '!($3<900) {print}' /etc/passwd //输出第3个字段不小于900的行
//“!”号表示取反
awk:可以使用条件表达式,条件表达式的运算涉及两个符号,冒号和问号,实质就是if...else语句的捷径,有着和if...else相同的效果。
awk -F : '{if($3>200) {print $0}}' /etc/passwd //输出第3个字段大于200的行
awk -F : '{max=($3>$4)?$3:$4;print max}' /etc/passwd
//如果第3个字段的值大于第4个字段的值,则把冒号前表达式的值赋给max,否则就将冒号后那个表达式的值赋给max
awk -F : '{max=($3>200)?$3:$1;print max}' /etc/passwd
//如果第3个字段的值大于200,则把第3个字段的值赋给max,否则就把第1个字段的值赋给max
按字段输出:
awk -F : '{print NR,$0}' /etc/passwd //输出行号和整行内容
awk -F : '$3<5 {print $1 $3}' /etc/passwd
//输出第3列小于5的第1列与第3列数据
awk -F : 'NR==3,NR==7 {print $1,$7}' /etc/passwd
//输出第3行到第7行中以冒号为分隔符的第1列与第7列的数据
awk -F ":" '($1~"root")&&(NF==7){print $1,$3}' /etc/passwd
//输出包含7个字段,并且第1个字段中包含root的行的第1与第3个字段内容
需要的话,输出数据时还可以插入一些文本标签:
awk -F ":" '{print $1":"$2":"$3":"$4}' /etc/passwd
//保留原来的格式,输出以冒号为分隔的前4个字段
awk -F : '{print $1,$3}' /etc/passwd //以冒号为分隔符,输出第1,3列
awk 'BEGIN{FS=":"}{print $1,$3}' /etc/passwd //以冒号为分隔符,输出第1,3列
//在FS之前加一个BEGIN,当读取第一条数据之前,先把分隔符加上后再去操作。
awk 'BEGIN{X=0};/\/bin\/bash$/{X++};END{print X}' /etc/passwd
//统计以/bin/bash为结尾的行数
awk执行顺序:
先执行BEGIN{ }中的操作;
再从指定的文件中逐行读取数据,自动更新NF、NR、$0、$1等内建变量的值,去s执行'模式或条件{编辑指定}';
最后指定END{ }中的后续操作。
处理命令输出的结果:awk可以利用管道符“|”处理命令的结果
date | awk '{print "Month:"$2"\nYear:",$6}'