三剑客

grep

grep
    -n 打印关键字所在的行号
    -A after 打印过滤内容后N行
    -B before 打印过滤内容前N行
    -C center 打印过滤内容前后N行
    -E (过滤多个内容) 支持正则
    过滤多个的时候用|去分隔
[root@web02 web02]# grep -E 'root|mysql' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
    -w 精致匹配
    -o 只打印关键字
    -v 取反
    -i 忽略大小写
[root@web02 web02]# grep root 1.txt
root
[root@web02 web02]# grep ROOT 1.txt
ROOT
[root@web02 web02]# grep -i ROOT 1.txt
root
ROOT
-q 静默输出
[root@web02 web02]# grep ROOT 1.txt
ROOT
[root@web02 web02]# grep -q ROOT 1.txt
-c 显示过滤内容的行数
[root@web02 web02]# cat 1.sh | grep -c 1
59
-l 对比关键字在那个文件之中
[root@web02 web02]# grep -l whiptail 1.sh 1.txt tb.sh
1.sh
tb.sh
-L 对比关键字不在那个文件中
[root@web02 web02]# grep -L whiptail 1.sh 1.txt tb.sh
1.txt
-r 递归检索文件
-h 只显示文件内容
-f 只过滤文件相同的内容
-vf 才是对比文件不同

sed

针对核心内容 增 删 改 查
sed的执行流程
1.sed是按行读取文件内容
2.没读取一行 会进行判断 判断是否是你要的行
3.如果不是 判断你有没有加-n
4.如果加了-n 就读取下一行
5.如果没有-n 会将所有内容输出到终端(默认输出)
6.如果是 把你要的那一行打印出来 在判断后续的执行动作(p d s a i c)
7.动作处理完毕之后 指定输出的内容
8.即便读取完毕,内容输出完毕,sed还会继续往后读读取值最后一行
-n 匹配你要的内容
不加-n 匹配你要的内容和全部内容

-p print打印
#不加-n打印
[root@web02 web02]# sed '2p' 1.txt 
1,wyd,666
2,hhh,777
2,hhh,777
3,wb,888
4,zdp,999
# 打印单独的行
[root@web02 web02]# sed -n '2p' 1.txt
2,hhh,777
# 打印多行
[root@web02 web02]# sed -n '1p;2p' 1.txt
1,wyd,666
2,hhh,777
[root@web02 web02]# sed -n '1p;3p' 1.txt
1,wyd,666
3,wb,888
[root@web02 web02]# sed -n '1,3p' 1.txt
1,wyd,666
2,hhh,777
3,wb,888
#   -n 取消默认输出
[root@web02 web02]# sed '2p' 1.txt
1,wyd,666
2,hhh,777
2,hhh,777
3,wb,888
4,zdp,999
[root@web02 web02]# sed -n '2p' 1.txt
2,hhh,777
# 模糊查询
[root@web02 web02]# sed -nr '/hh|d/p' 1.txt
1,wyd,666
2,hhh,777
4,zdp,999
# 范围模糊查找
[root@web02 web02]# sed -nr '/wyd/,/wb/p' 1.txt
1,wyd,666
2,hhh,777
3,wb,888
# sed模拟grep -A
[root@web02 web02]# sed -n '/wyd/,+2p' 1.txt
1,wyd,666
2,hhh,777
3,wb,888
# 模拟seq
[root@web02 web02]# seq 1 2 10
1
3
5
7
9
[root@web02 web02]# sed -n '1~2p' 1.txt
1,wyd,666
3,wb,888
# 取反
[root@web02 web02]# sed -n '/wyd/!p' 1.txt
2,hhh,777
3,wb,888
4,zdp,999

-d delete
cat 1.txt
1,wyd,666
2,hhh,777
3,wb,888
4,zdp,999
# 临时删除
[root@web02 web02]# sed -n '2d' 1.txt
[root@web02 web02]# sed '2d' 1.txt
1,wyd,666
3,wb,888
4,zdp,999
# 永久删除
[root@web02 web02]# sed -i '2d' 1.txt
[root@web02 web02]# cat 1.txt
1,wyd,666
3,wb,888
4,zdp,999
# 删除第一行
[root@web02 web02]# sed '1d' 1.txt
3,wb,888
4,zdp,999
# 删除最后一行
[root@web02 web02]# sed '$d' 1.txt
1,wyd,666
3,wb,888
# 删除包含hhh到最后一行
[root@web02 web02]# sed '/hhh/,$d' 1.txt
1,wyd,666
[root@web02 web02]# sed '1!d' 1.txt
1,wyd,666
# 删除wb到msx的行
[root@web02 web02]# sed '/wb/,/msx/d' 1.txt
1,wyd,666
2,hhh,777

命令 含义
c (replace)替代 替换这行的内容
a (append)追加 *重点 向指定的行或每一行追加内容 (相当于>>)【行的末尾追加】
i (insert)插入 向指定的行或每一行插入内容 (行的前面插入)

例:

#在txt中第四行下面追加一句jiujiu
[root@hadoop100 ~]# sed '4a jiujiu' txt 
#在txt中第四行上面追加一句jiujiu
[root@hadoop100 ~]# sed '4i jiujiu' txt
#把txt中第四行删除并改为jiujiu
[root@hadoop100 ~]# sed '4c jiujiu' txt

#语法:sed 's#xxx#xxx#g'2  
s:#想要的搜索内容#想替换的内容#g   
s:搜索                     g:全局

反向引用:

口诀:先保护,在使用

例:把hello,world前后反过来
[root@hadoop102 ~]# echo hello,world 
hello,world
[root@hadoop102 ~]# echo hello,world | sed -r 's#(^.*),(.*$)#\2 \1#g'
world hello

注:尽量使用#

awk

awk 是一个按需求格式化文本再进行输出的工具。和 sed 命令类似,awk 命令也是逐行扫描文件(从第 1 行到最后一行),寻找含有目标文本的行,如果匹配成功,则会在该行上执行用户想要的操作;反之,则不对行做任何处理。awk -f 脚本文件 数据文件  执行awk脚本文件
 awk 的应用场景:
看下 awk 能干些什么事情:
1. 能够将给定的文本内容,按照我们期望的格式输出显示,打印成报表。
2. 分析处理系统日志,快速地分析挖掘我们关心的数据,并生成统计信息;
3. 方便地用来统计数据,比如网站的访问量,访问的 IP 量等;
4. 通过各种工具的组合,快速地汇总分析系统的运行信息,让你对系统的运行了如指掌;
5. 强大的脚本语言表达能力,支持循环、条件、数组等语法,助你分析更加复杂的数据;
awk 不是万能的,它比较擅长处理格式化的文本,比如 日志、 csv 格式数据等;
[root@zabbix01 ~]# ls -l `which awk`
lrwxrwxrwx. 1 root root 4 6月 12 10:58 /usr/bin/awk -> gawk

平时我们使用,都是当做命令使用,所以我们称之为 单行脚本。那么awk能不能写脚本呢,必然可以,在linux系统中就有很多的jawk脚本

[root@zabbix01 ~]# find /usr/share/ -type f -name '*.awk'
/usr/share/awk/assert.awk
/usr/share/awk/bits2str.awk
/usr/share/awk/cliff_rand.awk
/usr/share/awk/ctime.awk
/usr/share/awk/ftrans.awk
/usr/share/awk/getopt.awk
/usr/share/awk/gettime.awk
/usr/share/awk/group.awk
/usr/share/awk/join.awk
/usr/share/awk/libintl.awk
/usr/share/awk/noassign.awk
/usr/share/awk/ord.awk
/usr/share/awk/passwd.awk
/usr/share/awk/quicksort.awk
/usr/share/awk/readable.awk
/usr/share/awk/rewind.awk
/usr/share/awk/round.awk
/usr/share/awk/strtonum.awk
/usr/share/awk/walkarray.awk
/usr/share/awk/zerofile.awk
举例:
# awk -F: 'BEGIN{print"-----header-----"} {print $1,$7} END{print"-----footer-----"}' /etc/passwd
*awk读取文件内容之前*
1.读取文件之前,先看命令的选项,例如 -F,-v
2.如果写了BEGIN{}则先在BEGIN{}中的指令
*awk读取文件内容之时*
1.awk在读取文件时,也是一行一行的读
2.读取一行之后,判断是否满足条件,如果是,则执行{对应动作}
{print $1}
awk -F , {print $1} 1.txt
3.如果不满足条件,awk继续读取下一行,直到满足条件或者到文件的最后一行
*awk读取文件内容之后*
1.所有文件读取完成之后,走END{}中的指令

awk结构

1. BEGIN 区域
Begin 区域的语法:
BEGIN { awk-commands }
BEGIN 区域的命令只最开始、在 awk 执行 body 区域命令之前执行一次。
BEGIN 区域很适合用来打印报文头部信息,以及用来初始化变量。
BEGIN 区域可以有一个或多个 awk 命令
关键字 BEGIN 必须要用大写
BEGIN 区域是可选的
2. body 区域
body 区域的语法:
/pattern/ {action}
body 区域的命令每次从输入文件读取一行就会执行一次
如果输入文件有 10 行,那 body 区域的命令就会执行 10 次(每行执行一次)
Body 区域没有用任何关键字表示,只有用正则模式和命令。
Body 区域是可选的
3. END 区域
END 区域的语法:
END { awk-commands }
END 区域在 awk 执行完所有操作后执行,并且只执行一次。
END 区域很适合打印报文结尾信息,以及做一些清理动作
END 区域可以有一个或多个 awk 命令
关键字 END 必须要用大写
END 区域是可选的
提示:如果命令很长,即可以放到单行执行,也可以用\折成多行执行。

行与列

名词 awk一些叫法 一些说明
记录(record) 每一行默认通过回车分割的
字段(field) 每一列默认通过空格分割的
awk中行与列结束的标记都是可以修改的
内置变量 功能
NF 当前处理的行的字段个数(就是:有多少列)
NR 当前处理的行的行号(就是:有多少行)例:NR==1[取出某一行]
FNR 读取文件的记录数(行号),从1开始,新的文件重新从1开始计数
$0 当前处理的行的整行内容(就是:表示一行的内容)
$n 当前处理行的第n个字段(就是:第n列)
FILENAME 被处理的文件名
FS 指定每行的字段分隔符,默认为空格或制表位(相当于选项 -F )
OFS 输出字段的分隔符,默认也是空格
RS 行分割符。awk从文件上读取资料时,将根据Rs的定义把资料切割成许多条记录,而awk一次仅读取一条记录,预设值是“\n“
ORS 输出分割符,默认也是换行符

1)取行

awk
NR==1 取出某一行
NR>=1&&(并且)NR<=5 取出1到5行范围
常用符号 > < = >= <= == !=(不等于)
/jiujiu/ //(双斜线搜索/过滤)
/xx/,/xx/ 例:[root@hadoop102 ~]# awk '/1/,/4/' like
1hello ,world
2like
4linux

2)取列

在awk中取列首先要认识-F

  • -F:指定分隔符,指定每一列结束标记(默认是空格/连续的空格/还有tab键)
  • $数字:表示取出某一列 注意:在awk中$内容一个意思,表示取出某一列
  • $0:表示整行的内容
  • 取列一般是{print xxx}
  • $NF:表示取最后一列

小结

  • 行与列的认知,[行:记录 列:字段/域]
  • awk取行与取列

awk模式匹配

awk -F"[ /]+" 'NR==2{print $2}'
命令 选项 ‘条件{动作}’
  • 比较符号:<(小于) >(大于) =(等于) >=(大于等于) <=(小于等于) !=(不等于)
  • 正则:
  • 范围: 表达式 ;
  • 特殊条件:BEGIN和END

1)比较表达式-参考上面取行部分

2)正则:

  • //(双划线) 支持扩展正则
  • awk可以精确到某一列,某一列中包含/不包含.......内容
  • ~ :包含
  • !~:不包含
正则 awk正则
^ 表示.....开头 某一列的开头 $2~/^like/ :第二列以like开头的
$ 表示.....结尾 某一列的结尾 $2~/like$/ :第二列以like结尾的
^$ 空行 某一列的空的 $2~/^$/ :第二列空行的
练习:
#找出第三列以2开头的行,并显示第一列,第三列,最后一列
文件:/etc/passwd
[root@hadoop102 ~]# awk -F: '$3~/^2/' /etc/passwd| awk -F : '{print $1,$3,$NF}'
#取找出第三列以1或者2开头的行,并显示第一列,第三列,最后一列
 awk -F: '$3~/^[12]/' /etc/passwd| awk -F : '{print $1,$3,$NF}'
 awk -F: '$3~/^1|^2/' /etc/passwd| awk -F : '{print $1,$3,$NF}'
 可以多种写法,主要看正则怎么写

3)表示范围

  • /从哪里开始/./哪里结束/ 常用
  • NR==1,NR==5 从第一行开始到第五行结束 类似于sed -n '1,5p'

4)特殊模式BEGIN{}和END{}

模式 含义 应用场景
BEGIN 里面的内容会在awk读取文件之前执行 1)进行简单的统计,计算,不涉及读取文件(常用
2)用来处理文件之前,添加个表头(了解)
3)用来定义awk变量(很少用,因为可以用-v)
END 里面的内容会在awk读取文件之后执行 1)awk进行统计,一般是过程;先进行计算,最后END里面输出结果(常用)
2)awk使用数组,用来输出数组结果(常用)
  • END{}统计计算

  • 统计方法:

    统计方法 简写形式 应用场景
    i++ i=i+1 计数型,统计次数
    sum=sum+?? sum+=?? 求和,累加
    注意:i sum 都是变量,可以随便写
    array[]=array[]+1 array[]++ 数组分类计算
统计/etc/service里面有多少个空行
[root@hadoop102 ~]# awk '/^$/{i++}END{print i}' /etc/services 
17
#求1到100的和
[root@hadoop102 ~]# seq 100|awk '{sum=sum+$1}END{print sum}'
5050
如果要显示过程则:
在条件后跟上print xxx
[root@hadoop102 ~]# seq 100|awk '{sum=sum+$1,print sum}END{print sum}'

5)awk数组

  • 统计日志:类似于统计个每个ip出现的字数,统计每种状态码出现的次数/统计系统中每个用户被攻击的次数等等...
  • 累加求和;统计每个ip消耗的流量
shell数组 awk数组
形式 array[0]=jiujiu array[1]=like array[0]=jiujiu array[1]=like
使用 echo $(array[0]) echo $(array[1]) print array[0] array[1]
批量输出数组内容 for i in $(array[*])
do
echo $i
done
for (i in array)
print i
print [i]
awk数组专用循环,变量获取到的是数组的下标,如果想要数组内容 用 a[i] 注释1
#awk数组一般定义和使用
[root@hadoop102 ~]# awk 'BEGIN{a[0]=jiujiu;a[1]=like; print a[0],a[1]}'

[root@hadoop102 ~]# #这里显示空白是因为在awk中字母会被识别为变量,如果只是想
[root@hadoop102 ~]# #使用字符串需要用双引号引起来
[root@hadoop102 ~]# #数字不受影响
[root@hadoop102 ~]# awk 'BEGIN{a[0]=123;a[1]=321; print a[0],a[1]}'
123 321
[root@hadoop102 ~]# awk 'BEGIN{a[0]="jiujiu";a[1]="like"; print a[0],a[1]}'
jiujiu like
#注释1:awk数组专用
[root@hadoop102 ~]# awk 'BEGIN{a[0]=123;a[1]=321; for (i in a) print i}'
0
1
[root@hadoop102 ~]# awk 'BEGIN{a[0]=123;a[1]=321; for (i in a) print a[i]}'
123
321

练习题:

#统计以下域名出现次数(用awk)
https://blog.driverzeng.com/index.html
https://blog.driverzeng.com/index.html
https://blog.driverzeng.com/index.html
https://blog.driverzeng.com/1.html
http://post.driverzeng.com/index.html
https://blog.driverzeng.com/1.html
https://blog.driverzeng.com/1.html
http://mp3.driverzeng.com/index.html
https://blog.driverzeng.com/1.html
https://blog.driverzeng.com/3.html
http://post.driverzeng.com/2.html
http://post.driverzeng.com/2.html
http://post.driverzeng.com/2.html
http://post.driverzeng.com/2.html
http://post.driverzeng.com/2.html
http://post.driverzeng.com/2.html

[root@hadoop102 ~]# cat 111 | awk -F '/' '{array[$3]++}END{for (i in array)print i,array[i]}' 111 
blog.driverzeng.com 8
post.driverzeng.com 7
mp3.driverzeng.com 1

#array[]++ 你要统计什么  []里面就是什么(某一列
#比如:统计access.log中ip出现的次数  array[$1]

注意:使用awk统计日志,尽量精确匹配

6)for循环/if判断

shell编程c语言for循环 awk for循环
for((i=1;i<=10;i++))
do
echo '$i'
down
for(i=1;1<=10;i++)
print i
awk for循环用来循环每个字段
例:
1+100的和
[root@hadoop102 ~]# awk 'BEGIN{for(i=1;i<=100;i++)sum+=i;print sum}'
5050

[root@hadoop102 ~]# awk 'BEGIN{
for(i=1;i<=100;i++)
    sum+=i;
print sum
}'
5050

if判断

shell if 判断 awk if 判断
if["who" -eq 20 ];then
echo ’成年人’
fi
if(条件)
print "成年人”
常用
if["who" -eq 20 ];then
echo ’成年人’
else
echo "未成年人“
fi
if(条件)
print "成年人”
else
print "未成年人“

例子:

if($1~/root/){
print $1
}
if(){
}else{
}
if(){
}else if(){
}else{
}
统计磁盘空间使用率,如果大于1%,则提示磁盘空间不足,并显示磁盘分区,磁盘使用率,磁盘挂载点
[root@hadoop102 ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 2.1G     0  2.1G   0% /dev
tmpfs                    2.1G     0  2.1G   0% /dev/shm
tmpfs                    2.1G   12M  2.1G   1% /run
tmpfs                    2.1G     0  2.1G   0% /sys/fs/cgroup
/dev/mapper/centos-root   45G  1.5G   44G   4% /
/dev/sda1                3.0G  138M  2.9G   5% /boot
tmpfs                    423M     0  423M   0% /run/user/0
[root@hadoop102 ~]# df -h | awk -F '[ %]+' 'NR>1{if($5>=1)print "disk no enough",$1,$5,$NF}'
disk no enough tmpfs 1 /run
disk no enough /dev/mapper/centos-root 4 /
disk no enough /dev/sda1 5 /boot
#注意:
awk使用多个条件的时候,第一个条件可以放在‘条件{动作}’ 第二个条件一般使用if判断

试题:

统计这段语句中,单词字符数小于6的单词 ,显示出来

Life is too short to spend time with people who suck the happiness out of you

[root@hadoop102 ~]# echo Life is too short to spend time with people who suck the happiness out of you
awk '{for(i=1;i<=NF;i++) if(length($i)<6) print $i}'
Life
is
too
short
to
spend
time
with
who
suck
the
out
of
you

awk函数

length:统计
[root@hadoop102 ~]# echo jiujiu | awk '{print length()}'
6
[root@hadoop102 ~]# echo jiujiu like | awk '{print length($1)}'
6
[root@hadoop102 ~]# echo jiujiu like | awk '{print length($2)}'
4
如果不属于$1/$2则默认$0整行输出

控制结束标语

#语法
-vRS=
[root@web02 web02]# awk -vRS=, '{print "这里是行号:"NR,"这里是每一行的内容:"$0}'
1.txt
这里是行号:1 这里是每一行的内容:1
这里是行号:2 这里是每一行的内容:wyd
这里是行号:3 这里是每一行的内容:666 wyd
2.hhh.777
3
这里是行号:4 这里是每一行的内容:wb
这里是行号:5 这里是每一行的内容:888
4.zdp.999
5
这里是行号:6 这里是每一行的内容:msx
这里是行号:7 这里是每一行的内容:000
6
这里是行号:8 这里是每一行的内容:wyd
这里是行号:9 这里是每一行的内容:123

## 修改输出后的内容分隔符
-vOFS=#
[root@web02 web02]# awk -F: -vOFS=\| '{print $1,$2,$3,$4,$5,$6,$7}' /etc/passwd
root|x|0|0|root|/root|/bin/bash
bin|x|1|1|bin|/bin|/sbin/nologin
daemon|x|2|2|daemon|/sbin|/sbin/nologin
adm|x|3|4|adm|/var/adm|/sbin/nologin
lp|x|4|7|lp|/var/spool/lpd|/sbin/nologin
sync|x|5|0|sync|/sbin|/bin/sync
shutdown|x|6|0|shutdown|/sbin|/sbin/shutdown
halt|x|7|0|halt|/sbin|/sbin/halt
mail|x|8|12|mail|/var/spool/mail|/sbin/nologin
operator|x|11|0|operator|/root|/sbin/nologin
games|x|12|100|games|/usr/games|/sbin/nologin
ftp|x|14|50|FTP User|/var/ftp|/sbin/nologin
nobody|x|99|99|Nobody|/|/sbin/nologin
systemd-network|x|192|192|systemd Network Management|/|/sbin/nologin
dbus|x|81|81|System message bus|/|/sbin/nologin
polkitd|x|999|998|User for polkitd|/|/sbin/nologin
sshd|x|74|74|Privilege-separated SSH|/var/empty/sshd|/sbin/nologin
postfix|x|89|89||/var/spool/postfix|/sbin/nologin
rpc|x|32|32|Rpcbind Daemon|/var/lib/rpcbind|/sbin/nologin
rpcuser|x|29|29|RPC Service User|/var/lib/nfs|/sbin/nologin
nfsnobody|x|65534|65534|Anonymous NFS User|/var/lib/nfs|/sbin/nologin
xxx|x|1000|1000||/home/xxx|/bin/bash
yys|x|1001|1001||/home/yys|/bin/bash
nginx|x|998|996|Nginx web server|/var/lib/nginx|/sbin/nologin
mysql|x|27|27|MariaDB Server|/var/lib/mysql|/sbin/nologin
xyz|x|1002|1002||/home/xyz|/bin/bash

练习题

# 找出姓氏是Zhang!!!!!!!!!!!的人 他们第二次捐款数量的数据和姓名
Zeng Laoshi 133411023 :110:100:75
Deng Ziqi 44002231 :250:10:88
Zhang Xinyu 877623568 :120:300:200
Gu Linazha 11029987 :120:30:79
Di Lireba 253097001 :220:100:200
Jiang Shuying 535432779 :309:10:2
Ju Jingyi 68005178 :130:280:385
Zhang Yuqi 376788757 :500:290:33
Wen Zhang 259872003 :100:200:300
# 解答
[root@web02 web02]# awk -F '[ :]+' 'BEGIN{print "姓名","捐款数额"}/^Zhang/{print $1,$2,$5}' user.txt
姓名 捐款数额
Zhang Xinyu 300
Zhang Yuqi 290
## 显示所有以25开头的qq号码和姓名
[root@web02 web02]# awk '$3 ~ /^25/{print $1,$2,$3}' user.txt
Di Lireba 253097001
Wen Zhang 259872003
## 显示所有QQ号最后一位是1/3的人 姓名和QQ
[root@web02 web02]# awk '$3 ~ /(1|3)$/{print $1,$2,$3}' user.txt
Zeng Laoshi 133411023
Deng Ziqi 44002231
Di Lireba 253097001
Wen Zhang 259872003
## 捐款显示$为分隔符
[root@web02 web02]# awk '{gsub(/:/,"$");print $0}' user.txt
Zeng Laoshi 133411023 $110$100$75
Deng Ziqi 44002231 $250$10$88
Zhang Xinyu 877623568 $120$300$200
Gu Linazha 11029987 $120$30$79
Di Lireba 253097001 $220$100$200
Jiang Shuying 535432779 $309$10$2
Ju Jingyi 68005178 $130$280$385
Zhang Yuqi 376788757 $500$290$33
Wen Zhang 259872003 $100$200$300

gsub("被替换的内容","替换的内容",第N列)
## 显示ifconfig中 范围是1~255的数字
ifconfig | awk -vRS='[^0-9]' '$0>=1 && $0<=255'

正则表达式

正则表达式,简写:re,全拼:(regular expression)
在某些地区,管它叫做,正规表达式、规则表达式
正则表达式的"祖先"可以一直上溯至对人类神经系统如何工作的早期研究。Warren McCulloch 和
Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。
1956 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题
为"神经网事件的表示法"的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为"正则集的
代数"的表达式,因此采用"正则表达式"这个术语。
随后,发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究,Ken
Thompson 是 Unix 的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的 qed 编辑器。
如他们所说,剩下的就是众所周知的历史了。从那时起直至现在正则表达式都是基于文本的编辑器和搜
索工具中的一个重要部分。

为什么使用正则

#主要目的:
1.方便处理文本和字符串内容
2.处理有规律的内容
3.正则一般给高级 开发语言 使用
例如:Python,Go,C++,JAVA等
awk 和 sed 也是一门语言
搜索和替换操作
但是一般的命令,搜索和替换缺乏灵活性,基本写死。
所以我们可以通过正则表达式,灵活的动态匹配文本。
例如:
1.可以测试输入字符串
以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
2.替换文本。
可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
回车 和 换行
\r
\n
3.基于模式匹配从字符串中提取子字符串。
4.查找文档内或输入域内特定的文本。 t

#正则和通配符的混淆
# 通配符
* 匹配所有
# 正则
*代表前面的字符出现0此或者多次

在linux中使用正则分为两部分

修饰符
元字符

# 基础正则
^ 以什么什么开头
$ 以什么什么结尾
. 任意字符
* 前面的字符出现零次或者多次
.*
[] 主要是一些范围 [0-9] [a-z]
[^] 这是取反 [^0-9]
^[0-9]  表示0-9的范围

# 拓展正则
+ 前面的一个字符或者多个字符出现一次或者的多次
awk -F '[: ]+' '{print $2}'
yys sasadasdasdasd 123:abc : 789
[root@web02 web02]# cat 3.txt | awk -F '[: ]+' '{print $1}'
yys
[root@web02 web02]# cat 3.txt | awk -F '[: ]+' '{print $5}'
789
| 或者
()被括号起来的东西视为一个整体
sed 里面做后巷引用 (.*)
{} 中间写一个非负整数,表示大括号前面的内容出现指定次数
[1-9].*
[1-9]+
[1-9]{1,3} 最少出现一次 最多出席那三次
# 匹配id
[1-90]{1,3}\.
# {}例子
[root@web02 web02]# grep -E 'z{3}'
z 没有匹配到
zz 没有匹配到
zzz 匹配到了

[root@web02 web02]# grep -E 'z{1,3}'
z 匹配到了
z 匹配到了
zz 匹配到了
zz 匹配到了
zzz 匹配到了
zzz 匹配到了
zzzz 匹配到了

正则表达式使用误区

## 通配符
* 代表所有内容
{} 只要是生产序列
[root@web02 web02]# echo {1..10}
1 2 3 4 5 6 7 8 9 10
[root@web02 web02]# echo {01..10}
01 02 03 04 05 06 07 08 09 10
[root@web02 web02]# echo {1..10..2}
1 3 5 7 9
[root@web02 web02]# echo {a..z..2}
a c e g i k m o q s u w y
cp /usr/lib/systemd/system/nginx.service{.bak}
cp /usr/lib/systemd/system/{nginx.service,nginx.service.bak}
? 匹配任意一个字符
[root@web02 web02]# ls -l ./s?udent.txt
-rw-r--r-- 1 root root 0 Jul 6 12:32 ./student.txt
[root@web02 web02]# ls -l ./s??dent.txt
-rw-r--r-- 1 root root 0 Jul 6 12:32 ./student.txt
[root@web02 web02]# ls -l ./???????.txt
-rw-r--r-- 1 root root 0 Jul 6 12:32 ./student.txt
[root@web02 web02]# touch hhh.txt
[root@web02 web02]# ls -l ./???.txt
-rw-r--r-- 1 root root 0 Jul 6 12:33 ./hhh.tx
[]
[^]
[root@web02 web02]# touch /tmp/check_{1..10}.txt
[root@web02 web02]# ls -l /tmp/check_[0-9].txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_1.txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_2.txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_3.txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_4.txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_5.txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_6.txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_7.txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_8.txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_9.txt
[root@web02 web02]# ls -l /tmp/check_[0-9][0-9].txt
-rw-r--r-- 1 root root 0 Jul 6 12:34 /tmp/check_10.txt

正则表达式使用注意事项

1.所有符号皆为英文符号
2.使用三剑客时加引号
3.注意字符集,如果出现字符集问题,那么将字符集修改为C(小概率事件)
4.像素眼(空格,换行符,tab键)
5.测试的时候,推荐使用grep -E或者egrep,因为过滤出来的内容会加颜色
[root@web02 ooo]# cat 1.txt
/tmp /check_1.txt
/tmp /check_2.txt
[root@web02 ooo]# awk '/\t/{print}' 1.txt
/tmp /check_2.txt
\t = tab
[root@web02 ooo]# awk '/ /{print}' 1.txt
/tmp /check_1.txt

#grep -E / egrep
[root@web02 ooo]# egrep 'root|mysql' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
[root@web02 ooo]# grep -E 'root|mysql' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
[root@web02 ooo]# grep '.*' /etc/passwd
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@web02 ooo]# grep '.' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

-o 只显示匹配内容
grep -o '.*' /etc/passwd
.任意字符
grep -o '.' /etc/passwd
.任意字符

正则表达式的修饰符

用来做标记的
标记也称为修饰符,正则表达式的标记用于指定额外的匹配策略。
标记不写在正则表达式里,标记位于表达式之外,格式如下:

/pattern/flags
/正则表达式/标记
%s###g
在Linux中,正则表达式修饰符m(多行模式)用于指定多行文本匹配模式。当使用m修饰符时,某些元字符
(如^和$)的行为会发生变化,以实现跨越多行进行匹配。
具体来说,在m修饰符下,以下元字符的含义会发生改变:
^(脱字符):通常情况下,^匹配文本的开头。在m修饰符下,^将匹配每一行的开头。
$(美元符号):通常情况下,$匹配文本的结尾。在m修饰符下,$将匹配每一行的结尾。
.(点号):通常情况下,.匹配除了换行符\n之外的任意字符。在m修饰符下,.将匹配包括换行符在内的任意
字符。
这里是一个示例,演示了m修饰符的具体用法:
bash
# 多行匹配示例
text='
Hello
World
'
# 不使用 m 修饰符的正则表达式
echo "$text" | grep '^H.*d$'
# 输出:Hello
# 使用 m 修饰符的正则表达式
echo "$text" | grep -P '(?m)^H.*d$'
# 输出:
# Hello
# World
在上面的示例中,我们使用了两种不同的grep命令来匹配文本。第一个命令grep '^H.*d$'没有使用m修饰
符,只匹配了以H开头且以d结尾的文本行,所以只输出了Hello。而第二个命令grep -P '(?m)^H.*d$'使
用了m修饰符(通过-P选项启用Perl正则表达式模式),成功地匹配了整个多行文本,并输出了所有匹配的
行。
sed -i 's#查找内容#替换内容#g'

正则表达式元字符

.(点):匹配任意一个字符,除了换行符。
^(脱):匹配输入字符串的开始位置3. $:匹配输入字符串的结束位置。
*:匹配前面的表达式零次或多次。
+:匹配前面的表达式一次或多次。
?:匹配前面的表达式零次或一次。
\d:匹配一个数字字符,相当于 [0-9]。
\D:匹配一个非数字字符,相当于 [^0-9]。
\w:匹配一个字母、数字或下划线字符,相当于 [A-Za-z0-9_]。
\W:匹配一个非字母、数字或下划线字符,相当于 [^A-Za-z0-9_]。
\s:匹配一个空白字符,包括空格、制表符、换页符等。
\S:匹配一个非空白字符。
[]:用来表示字符集合,匹配方括号中的任意一个字符。
[^]:用来表示排除字符集合,匹配除了方括号中的字符以外的任意一个字符。
():用来分组匹配,可以通过使用|(或)来选择分组中的内容。
{}:指定前面表达式的重复次数,{n}表示重复n次,{n,}表示重复至少n次,{n,m}表示重复n到m次。
\:用于转义字符,使其失去特殊意义
[root@web02 ooo]# echo -e 'abc\t123'
abc 123
[root@web02 ooo]# echo -e 'abc\v123'
abc
    123
[root@web02 ooo]# echo -e 'abc\v123\v456'
abc
    123
        456
[root@web02 ooo]# echo -e 'abc\f123'
abc
    123
[root@web02 ooo]# echo -e 'abc\f123\f456'
abc
    123
        456
\f 换页符
\b匹配单词的边界
[root@web02 ooo]# useradd abcnginx
[root@web02 ooo]# useradd nginx11
[root@web02 ooo]# grep -E '\bnginx\b' /etc/passwd
nginx:x:998:996:Nginx web server:/var/lib/nginx:/sbin/nologin
[root@web02 ooo]# grep -E 'nginx' /etc/passwd
nginx:x:998:996:Nginx web server:/var/lib/nginx:/sbin/nologin
abcnginx:x:1003:1003::/home/abcnginx:/bin/bash
nginx11:x:1004:1004::/home/nginx11:/bin/bash
[root@web02 ooo]# grep -E '\bnginx\b' /etc/passwd
nginx:x:998:996:Nginx web server:/var/lib/nginx:/sbin/nologin
[root@web02 ooo]# grep -E '\bnginx' /etc/passwd
nginx:x:998:996:Nginx web server:/var/lib/nginx:/sbin/nologin
nginx11:x:1004:1004::/home/nginx11:/bin/bash
[root@web02 ooo]# grep -E 'nginx\b' /etc/passwd
nginx:x:998:996:Nginx web server:/var/lib/nginx:/sbin/nologin
abcnginx:x:1003:1003::/home/abcnginx:/bin/bash
\B
# nginx的两边都得带东西才能被匹配出来
[root@web02 ooo]# grep -E '\Bnginx\B' /etc/passwd
123nginxabc:x:1005:1005::/home/123nginxabc:/bin/bash
\d 匹配一个数字字符
\ 转义符 让特殊符号失去本身自身作用
# \n换行符
[root@web02 ooo]# echo -e 'a\nb'
a
b
# \r 回车
[root@web02 ooo]# echo -e 'a\rb'
b
# \t tab
[root@web02 ooo]# echo -e 'a\tb'
a b
# \v垂直制表符
[root@web02 ooo]# echo -e 'a\vb\vc'
a
b
c
# \f换页
# \b单词边界
[root@web02 ooo]# grep -E '\bnginx' /etc/passwd
nginx11:x:1004:1004::/home/nginx11:/bin/bash
[root@web02 ooo]# grep -E 'nginx\b' /etc/passwd
abcnginx:x:1003:1003::/home/abcnginx:/bin/bash
# \B单词非边界
[root@web02 ooo]# grep -E '\Bnginx\B' /etc/passwd
123nginxabc:x:1005:1005::/home/123nginxabc:/bin/bash
#\d 代表一个数字
[root@web02 ooo]# grep -Po '\d' 2.txt
1
2
3
4
5
[root@web02 ooo]# grep -E '\d' 2.txt
# \w 匹配包括下划线的任意字符(^[A-Z a-z 0-9])
[root@web02 ooo]# grep -Po '\w' 2.txt
1
2
3
4
5
A
a
# \W 匹配非单词字符串 (^[A-Z a-z 0-9])
[root@web02 ooo]# grep -Po '\W' 2.txt
!
#
!
!
!
!
# \s 匹配任意就空白字符 空格 制表符 换页符 [^\f\n\r\t\v]
[root@web02 ooo]# grep -Po '\s' 2.txt
# \S 匹配任何非空白字符 [^\f\n\r\t\v]
[root@web02 ooo]# grep -Po '\S' 2.txt
1
2
3
4
5
A
a
h
e
l
l
o
!
#
!
!
!
!

练习

#1.匹配身份证号
[1-9][0-9]{16}([0-9]|x)
#2.匹配手机号
^1[3-9][0-9]{9}
#3.后项引用
(.*) 1
#4.给用户传参中间加上空格(后项引用)
echo 123456
sed -r 's#(.*)#<\1>#g'
sed -r 's#(.)#<\1>#g'
echo {1..10} 带空格的每个都加上<>

#5.过滤IP 
#6.过滤文件中,oldboy和oldbey的内容
#7.统计上面文件的单词数量
#8.统计上面文件的字母数量
#9.取出下面的指定内容
19:09:03 up 735 days, 23:12, 2 users, load average: 0.00, 0.03, 0.05
19:09:42 up 10:20, 3 users, load average: 0.00, 0.02, 0.05
19:11:24 up 0 min, 1 user, load average: 0.31, 0.08, 0.03
# 如何截取上面的登录用户数?
# 如何截取上面的开机时间?
## 因为在Linux中,我们目前只能使用awk grep sed取,而且支持的正则也是基础正则和扩展正则
## 但是有些元字符,基础和扩展正则也不支持,我们只能使用其他语言的正则,比如python
## 于是,在grep命令中,提供了一个选项叫做 -P 这个选项的作用就是,使用perl语言的正则
uptime| grep -Po '[0-9]+(?= user)'
uptime|grep -Po '\d+(?= user)'
uptime|grep -Po '(?<=up).*(?=[0-9] user)'
uptime|grep -Po '(?<=up).*(?=\d user)'