目录

Linux正则匹配详解

前言

对于正则表达式,相信很多人都知道,但是很多人的第一感觉就是难学,因为看第一眼时,觉得完全没有规律可寻,而且全是一堆各种各样的特殊符号,完全不知所云。

其实只是对正则不了解而以,了解了你就会发现,原来就这样啊正则所用的相关字符其实不多,也不难记,更不难懂,唯一难的就是组合起来之后,可读性比较差,而且不容易理解,本文旨在让大家对正则有一个基本的了解,能看得懂简单的正则表达式,写得出简单的正则表达式,用以满足日常开发中的需求即可。

0\d{2}-\d{8}|0\d{3}-\d{7} 先来一段正则,如果你对正则不了解,是不是完全不知道这一串字符是什么意思?这不要紧文章会详细解释每个字符的含义的。

什么是正则表达式

正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去匹配符合规则的字符。

正则字符简单介绍

元字符介绍

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
"^": ^会匹配行或者字符串的起始位置,有时还会匹配整个文档的起始位置.

"$": $会匹配行或字符串的结尾.

"\b": 不会消耗任何字符只匹配一个位置,常用于匹配单词边界 如 我想从字符串中"This is Regex"匹配单独的单词 "is" 正则就要写成 "\bis\b",\b 不会匹配is 两边的字符,但它会识别is 两边是否为单词的边界.

"\d": 匹配数字,例如要匹配一个固定格式的电话号码以0开头前4位后7位,如0737-5686123,正则:^0\d\d\d-\d\d\d\d\d\d\d$.

"\w": 匹配字母,数字,下划线,例如我要匹配"a2345BCD__TTz" 正则:"\w+",这里的"+"字符为一个量词指重复的次数.

"\s": 匹配空格,例如字符 "a b c" 正则:"\w\s\w\s\w"  一个字符后跟一个空格,如有字符间有多个空格直接把"\s" 写成 "\s+" 让空格重复.

".": 匹配除了换行符以外的任何字符,这个算是"\w"的加强版了"\w"不能匹配空格,如果把字符串加上空格用"\w"就受限了,看下用"."是如何匹配字符"a23 4 5 B C D__TTz"  正则:".+"

"[abc]": 字符组,匹配包含括号内元素的字符 

几种反义

1
2
3
4
5
"\W"      匹配任意不是字母,数字,下划线 的字符
"\S"      匹配任意不是空白符的字符
"\D"      匹配任意非数字的字符
"\B"      匹配不是单词开头或结束的位置
"[^abc]"  匹配除了abc以外的任意字符

量词

贪婪(贪心),如"*“字符 贪婪量词会首先匹配整个字符串,尝试匹配时,它会选定尽可能多的内容,如果失败则回退一个字符,然后再次尝试回退的过程就叫做回溯,它会每次回退一个字符,直到找到匹配的内容或者没有字符可以回退。相比下面两种贪婪量词对资源的消耗是最大的.

懒惰(勉强),如 “?” 懒惰量词使用另一种方式匹配,它从目标的起始位置开始尝试匹配,每次检查一个字符,并寻找它要匹配的内容,如此循环直到字符结尾处.

占有,如”+" 占有量词会覆盖事个目标字符串,然后尝试寻找匹配内容,但它只尝试一次,不会回溯,就好比先抓一把石头,然后从石头中挑出黄金.

"(贪婪): 重复零次或更多,例如"aaaaaaaa”,匹配字符串中所有的a,正则: “a",会出到所有的字符"a”

“+"(懒惰): 重复一次或更多次,例如"aaaaaaaa” 匹配字符串中所有的a,正则: “a+",会取到字符中所有的a字符,“a+“与"a*“不同在于”+“至少是一次而”*” 可以是0次.

“?"(占有): 重复零次或一次,例如"aaaaaaaa” 匹配字符串中的a,正则: “a?",只会匹配一次,也就是结果只是单个字符a.

“{n}": 重复n次,例如从"aaaaaaaa” 匹配字符串的a 并重复3次,正则: “a{3}“结果就是取到3个a字符"aaa”;

“{n,m}": 重复n到m次,例如正则 “a{3,4}” 将a重复匹配3次或者4次,所以供匹配的字符可以是三个"aaa"也可以是四个"aaaa” 正则都可以匹配到.

“{n,}": 重复n次或更多次,与{n,m}不同之处就在于匹配的次数将没有上限,但至少要重复n次 如 正则"a{3,}",a至少要重复3次

懒惰限定符

?": 重复任意次,但尽可能少重复,例如"acbacb”,正则"a.?b” 只会取到第一个"acb” 原本可以全部取到但加了限定符后,只会匹配尽可能少的字符,而"acbacb"最少字符的结果就是"acb”.

“+?": 重复1次或更多次,但尽可能少重复,与上面一样,只是至少要重复1次

“??": 重复0次或1次,但尽可能少重复,例如 “aaacb” 正则 “a.??b” 只会取到最后的三个字符"acb”

“{n,m}?": 重复n到m次,但尽可能少重复,例如 “aaaaaaaa” 正则 “a{0,m}” 因为最少是0次所以取到结果为空

“{n,}?": 重复n次以上,但尽可能少重复,例如 “aaaaaaa” 正则 “a{1,}” 最少是1次所以取到结果为"a”.

grep 正则表达式

grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。

grep常用用法

1
2
3
4
5
6
7
8
grep [-acinv] [--color=auto] '搜寻字符串' filename
选项与参数:
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 '搜寻字符串' 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
--color=auto :可以将找到的关键词部分加上颜色的显示喔!

sed 正则表达式

sed 用法

1
2
# 批量替换
sed -i "s/oldstring/newstring/g" grep oldstring -rl path

awk 正则表达式

awk 语法

1
awk `/REG/{action}`

awk可以读取后接的文件,也可以读取来自前一命令的标准输入,它分别扫描输入数据的每一行,查找当前扫描行中pattern是否匹配。如果匹配,则进行后续动作action。如果pattern不匹配或action部分处理完毕,则继续处理下一行,直到结束。

1
2
3
4
5
6
awk '{ 

     BEGIN{...}    #执行前语句
     pattern{...}     #每一行都会处理的语句,可以有多个
     END{...}       #执行后要处理的语句
}'

其中BEGIN为处理文本前的操作,一般用于改变FS,OFS,RS,ORS等,BEGIN部分完成之后,awk读取第一行输入,并将第一行的数据填入$0,$1,$2,..,$n,NR,NF等变量,然后进入正式处理阶段,待所有行处理完毕之后,进入END部分,END一般用于总结,打印报表等。

正式处理是一个内建的循环,每一次循环读取一行数据(默认RS为换行符),pattern{…}部分可以有多个,它可以使用正则匹配/RE/,算术运算符>,<,…,逻辑运算符&&,||等,当pattern没有时,也即不需要匹配条件,后面的动作{…}会在每一行都执行.

awk 内置变量

变量 用法
$0 当前记录(这个变量中存放着整个行的内容)
$1-$n 当前记录的第n个字段,字段间由FS分隔
FS 输入字段分隔符 默认是空格或者\t
NF 当前记录的字段个数 就是有多少列
NR 已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中
FNR 当前记录数,与NR不同的是,这个值会是各个文件自己的行号
RS 输入的记录分隔符,默认为换行符
OFS 输出字段分隔符,默认为空格
ORS 输出的记录分隔符,默认为换行符
FILENAME 当前输入文件的名字

awk运算符合正则匹配

算术运算符

  • awk算术运算符: !=,>,<,>=,<=

逻辑运算符

  • &&多个条件且||多个条件或

正则匹配

  • awk使用的RE为扩展正则表达式,匹配格式为/reg/
  • 定位行:
    • NR==行号
    • 用RE: /^Disk/
  • 字符串匹配: ~匹配!~不匹配
  • /reg/在整行范围内匹配reg,匹配到就执行后续动作
  • !/reg/ 整行没匹配到reg,才执行后续的动作
  • $1~/reg/只在第一字段匹配reg
  • $1!~/reg/ 第一个字段不匹配
  • NR >=2 从第二行开始处理

awk 整则可以和比较运算符结合使用,以便处理更复查的匹配

awk技巧

  • awk使用的RE为ERE
  • 如果在BEGIN中设置了OFS,只有$0有改动OFS才能生效
  • printfprint的区别: printf不自动打印换行符,print则自动打印换行符
  • gsub的返回值并不是替换后的字符串,而是返回替换的次数
  • 字符串常量一定用在"“包围起来,否则当做变量使用,如$1=="ipaaad"
  • awk的for循环为C-Style即为for(),区别于shell中的for i in ...
  • awk中可以使用多个分隔符,要封装在方括号里,用'‘包围,以防shell对他们进行解释,如awk -F '[:/t]',使用空格,冒号,tab作为分隔符
  • next语句: 从输入文件中取得下一个输入行,在awk命令表顶部重新执行命令,一般用于跳过一些特殊的行
  • awk匹配多个条件: `awk ‘/kobe/ && /james/’, 这会匹配的同时有kobe和james的行
  • FS默认值是[/t/n]+,OFS的默认值为空格,RS,ORS的默认值都是换行
  • exit语句: 终止AWK程序,但不跳过END语句
  • {s1;s2;s3;...}中多个语句用分号隔开if;else if;else
  • print后不带任何参数时,相当于print $0,将会打印整行记录

awk用法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 统计数据
cat xx.log |awk '{a[$1]+=1;} END {for(i in a){print a[i]" "i;}}'
#字符串截取
echo "123456789" | awk '{print substr($0, 5, 2)}'
# 从第二列开始打印
awk -F ":" '{for (i=2;i<=NF;i++)printf("%s ", $i);print ""}' xx
# 统计行数
awk 'END{print NR}' test1.sh
# 排序输出
sort -n -k1 kafka_production_12|awk -F ":" '{for (i=1;i<=NF;i++)printf("%s ", $i);print ""}'|awk '$2>=1634486400000 && $2<=1634572800000 {print $0}' > kafka_production_10-18-00-00-00-10-19-00-00-00
# 统计IP
awk '{i=$1;count[i]++}END{for(i in count)print(i,count[i])}' /var/log/httpd/access_log
# 统计访问次数最多
awk '{a[$1] += 1;} END {for (i in a) printf("%d %s\n", a[i], i);}' /var/log/httpd/access_log | sort -n | tail -n 10
# 添加表头
awk 'BEGIN {print "ID\tTime"}{printf("%s\t%s\n",$1,$2)| "sort -k1,1 -u -r"}' /var/log/httpd/access_log
# 定制表头
awk 'BEGIN{print "姓名 语文 数学 英语 总成绩"; \
sum1=0;sum2=0;sum3=0;sumall=0} \
{printf "%5s%5d%5d%5d%5d\n",$1,$2,$3,$4,$2+$3+$4;\
sum1+=$2;sum2+=$3;sum3+=$4;sumall+=$2+$3+$4}\
END{printf "%5s%5d%5d%5d%5d\n","总成绩",sum1,sum2,sum3,sumall}'\
 score.txt | column -t
# awkif使用
awk '{ if($1 == "xxx-'"$i"'")print $2}'

split 使用

1
2
3
4
# 按大小切割
split -b 500M xx.log -d -a 2 newfile_
# 按行数切割
split -l 100000 xx.log -d -a 2 newfile_

truncate 使用