三剑客:grep 、awk 、sed
grep
作用:过滤内容的行
# grep过滤文件内容
( grep '[a-z]' 文件名 过滤出a-z所有字母、grep '[a-Z]'或 '[a-zA_Z]' 文件名 过滤出a-zA-Z的所有字母)
grep '关键字' 文件名(单引号不加也行)
^ 以某关键字开头
$ 以某关键字结尾
.* 匹配所有
# 选项
-E 过滤多个关键字,支持正则(关键字之间用|隔开,关键字|关键字)
-v 取反 显示除关键字之外的内容
-n 显示行号(grep -n 关键字 文件名 即可显示关键字所在行号)
-A 过滤关键字行的后行(-A2就是过滤关键字后2行)
-B 过滤关键字行的前行(-B3就是过滤关键字前3行)
-C 过滤关键字行的前后行(-C2就是过滤关键字前后2行)
-w 精准匹配,以单词为过滤(显示关键字及同行内容)
-o 只显示过滤内容(只显示关键字)
-i 不区分大小写 (例:grep 'd' 文件名 就会过滤出d和D)
-q 静默输出
-c 统计关键内容行数
-l 查看关键字在那个文件里,并输出关键字所在的文件名(grep -l nm 1.txt 2.txt)
-L 对比关键字不在那个文件中
-r 递归检索文件 (需要知道被改的内容是什么)grep -r '被改内容' ./ 即可打印出被改的文件名及路径
-h 只显示文件内容
-f 对比文件内容,只过滤出文件相同的内容
-vf 对比文件不同
-F 以列表形式列出有关键字的文件名及关键字
-m 列出含有关键字的前n行 (grep -m 10 'aaa' 文件名)
-x 只显示与关键字匹配完全符合的 (grep -x 'abc.123' 文件名)
# 选项用法
-n 过滤内容并标注行号
[root@web02 web02]# grep -n '666' 1.txt
1:1,wyd,666
[root@web02 web02]# grep -n '77' 1.txt
2:2,hhh,777
[root@web02 web02]# grep -n 'wb' 1.txt
3:3,wb,888
[root@web02 web02]# grep -n 'zdp' 1.txt
4:4,zdp,999
-A 过滤内容后N行
[root@web02 web02]# grep -A 2 '666' 1.txt
1,wyd,666
2,hhh,777
3,wb,888
-B 过滤内容前N行
[root@web02 web02]# grep -B 2 '999' 1.txt
2,hhh,777
3,wb,888
4,zdp,999
-C 过滤内容前后N行
[root@web02 web02]# grep -C 1 '888' 1.txt
2,hhh,777
3,wb,888
4,zdp,999
-w 精致匹配
[root@web02 web02]# ifconfig | grep -w inet
inet 10.0.0.8 netmask 255.255.255.0 broadcast 10.0.0.255
inet 127.0.0.1 netmask 255.0.0.0
# 区别!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[root@web02 web02]# ifconfig | grep inet
inet 10.0.0.8 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::20c:29ff:fe09:a01f prefixlen 64 scopeid 0x20<link>
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
-o 只打印关键字
[root@web02 web02]# ifconfig | grep -o inetinet
inet
inet
inet
inet
-v 取反
[root@web02 web02]# ifconfig | grep -v inet
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 00:0c:29:09:a0:1f txqueuelen 1000 (Ethernet)
RX packets 225285 bytes 107040095 (102.0 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 124492 bytes 28950368 (27.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 00:0c:29:09:a0:29 txqueuelen 1000 (Ethernet)
RX packets 247 bytes 41447 (40.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2708 bytes 458343 (447.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
loop txqueuelen 1000 (Local Loopback)
RX packets 57 bytes 9842 (9.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 57 bytes 9842 (9.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
-i 忽略大小写
[root@web02 web02]# grep nb 2.txt
nb
[root@web02 web02]# grep NB 2.txt
NB
NB!!!
[root@web02 web02]# grep -i nb 2.txt
nb
NB
NB!!!
-q 静默输出
[root@web02 web02]# grep -i nb 2.txt
nb
NB
NB!!!
[root@web02 web02]# grep -iq nb 2.txt
-c 统计过滤内容的行数
[root@web02 web02]# cat 2.txt | grep -c nb
1
[root@web02 web02]# cat 2.txt | grep -c NB
2
-l 对比关键子在那个文件中
[root@web02 web02]# grep -l nb 1.sh tb.sh 1.txt 2.txt
2.txt
-L 对比关键字不在那个文件之中
[root@web02 web02]# grep -L nb 1.sh tb.sh 1.txt 2.txt
1.sh
tb.sh
1.txt
-r 递归检索文件
-h 只显示文件内容
-f 只显示文件相同内容
[root@web02 web02]# grep -f 3.txt 4.txt
123
456
789
[root@web02 web02]# grep -vf 3.txt 4.txt
321
-F 带关键字的内容列表形式展开
[root@web02 web02]# grep -F '1' 1.txt 2.txt 3.txt 1.sh
1.txt:1,wyd,666
3.txt:123
4.txt:123
1.sh:lb01=10.0.0.5
-m 列出含有关键字的前n行(加 -m 只显示关键字行,直接 -num 显示关键字前后各n行)
[root@web02 web02]# grep -6 'root' /etc/passwd
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
`root:x:0:0:root:/root:/bin/bash
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
-x 只匹配全部关键字的行
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
[root@web02 web02]# grep -x 'rpc:x:32:32:Rpcbind
Daemon:/var/lib/rpcbind:/sbin/nologin' /etc/passwd
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
-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
[root@web02 web02]# grep 'root|mysql' /etc/passwd
sed
sed针对的核心内容:增、删、改、查
sed命令的执行流程
1.sed先是按行读取文件内容 2.每读取一行内容,都会进行一次判断,是不是你想要的行 3.如果不是,则判断是不是加了-n选项 4.如果加了-n,就读取下一行 5.如果没加-n,就会将所有内容输出到命令行(默认输出) 6.如果是,你想要的那一行(第三行)则判断执行的后续动作(p d s a i c) 7.动作处理完成后,输出指定的内容 8.即便是读取完了,内容也输出了,sed也会继续往后读,直到文件的最后一行
-n 匹配你要的内容 不加-n 匹配你要的内容和全部内容
sed 查
`p print打印/显示
# 加-n 只打印想要的行,不加-n,打印想要的行及所有行
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
3,wb,888
4,zd,999
##加-n(取消默认输出)
[root@web01 ~]# sed -n '3p' 1.test
3,wb,888
##不加-n
[root@web01 ~]# sed '3p' 1.test
1,wy,666
2,hh,777
3,wb,888
3,wb,888
3,wb,888
4,zd,999
##打印多行
##打印第一行和第三行
[root@web01 ~]# sed -n '1p;3p' 1.test
1,wyd,666
3,wb,888
##打印一到三行
[root@web01 ~]# sed -n '1,3p' 1.test
1,wy,666
2,hh,777
3,wb,888
`# sed 模糊查询
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
[root@web01 ~]# sed -n '/wy/p' 1.test
1,wy,666
[root@web01 ~]# sed -n '/6/p' 1.test
1,wy,666
[root@web01 ~]# sed -n '/,/p' 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
# -nr 查找多个
[root@web01 ~]# sed -nr '/wb|wy/p' 1.test
1,wy666
3,wb,888
[root@web01 ~]# sed -nr '/wb|wy|hh/p' 1.test
1,wyd,666
2,hhh,777
3,wb,888
[root@web01 ~]# sed -nr '/wb|wy|,/p' 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
# 范围模糊查找(wy到wb)
[root@web01 ~]# sed -nr '/wy/,/wb/p' 1.test
1,wy,666
2,hh,777
3,wb,888
`# sed模拟grep -A (过滤关键字及其后nim行)
[root@web01 ~]# sed -n '/hh/,+2p' 1.test
2,hh,777
3,wb,888
4,zd,999
`# 过滤从关键字开始到第num行
[root@web01 ~]# sed -n '/hh/,4p' 1.test
2,hh,777
3,wb,888
4,zd,999
`# 模拟seq`
[root@web01 ~]# seq 1 2 10
1
3
5
7
9
[root@web01 ~]# sed -n '1~2p' 1.test
1,wy,666
3,wb,888
`# 取反`
[root@web01 ~]# sed -n '/wy/!p' 1.test
2,hh,777
3,wb,888
4,zd,999
sed删
`d delete
# 临时删除
[root@web01 ~]# sed '2d' 1.test
1,wy,666
3,wb,888
4,zd,999
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
# 永久删除(-i)
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
[root@web01 ~]# sed -i '2d' 1.test
[root@web01 ~]# cat 1.test
1,wy,666
3,wb,888
4,zd,999
# 删除第一行
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
[root@web01 ~]# sed '1d' 1.test
2,hh,777
3,wb,888
4,zd,999
# 删除最后一行
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
[root@web01 ~]# sed '$d' 1.test
1,wy,666
2,hh,777
3,wb,888
# 删除某个范围(例hhh到最后一行)
[root@web02 web02]# sed '/hh/,$d' 1.txt
1,wy,666
[root@web02 web02]# sed '1!d' 1.txt
1,wy,666
# 删除多个(删除wb到msx的行)
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
5,ms,000
[root@web01 ~]# sed '/wb/,/ms/d' 1.test
1,wy,666
2,hh,777
# 删除多个(删除第三行和第五行)(临时删)
[root@web01 ~]# sed '3d;5d' 1.test
1,wy,666
2,hh,777
4,zd,999
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
5,ms,000
sed增
cai
`a append 在下一行追加
# 在第二行下面追加*,lj,111
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
5,ms,000
[root@web01 ~]# sed '2a*,lj,111' 1.test
1,wy,666
2,hh,777
*,lj,111
3,wb,888
4,zd,999
5,ms,000
`i insert 在前面插入
# 在最后一行上面插入6*,zhy,222
[root@web01 ~]# sed '$i6*,zhy,222' 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
6*,zhy,222
5,ms,000
# 在第三行上面插入7*,zhy,222
[root@web01 ~]# sed '3i7*,zhy,222' 1.test
1,wy,666
2,hh,777
7*,zhy,222
3,wb,888
4,zd,999
5,ms,000
`c replace 替换整行
# 把第三行替换成0,000,000
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
5,ms,000
[root@web01 ~]# sed '3c0,000,000' 1.test
1,wy,666
2,hh,777
0,000,000
4,zd,999
5,ms,000
替换最后一行就是sed '$c000,000,000' 1.test
sed改
s substitute 替换
g global 全局
s###g ##末行模式替换用:%s###g
s///g
s@@@g
# 把wy替换成ww
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
5,ms,000
[root@web01 ~]# cat 1.test | sed s#wy#ww#g
1,ww,666
2,hh,777
3,wb,888
4,zd,999
5,ms,000
# 正则
[root@web01 ~]# cat 1.test | sed 's#[0-9]#666#g'
666,wy,666666666
666,hh,666666666
666,wb,666666666
666,zd,666666666
666,ms,666666666
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
5,ms,000
练习 用sed截取内网IP
# 用sed截取内网IP
[root@web01 ~]# ifconfig eth0 | sed -nr 's#^.*inet (.*) net.*$#\1#gp'
10.0.0.7
[root@web01 ~]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.0.7 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::20c:29ff:fe64:6a35 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:64:6a:35 txqueuelen 1000 (Ethernet)
RX packets 130475 bytes 52913678 (50.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 73376 bytes 14765349 (14.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
## 解析
inet 10.0.0.7 netmask 255.255.255.0 broadcast 10.0.0.255
ifconfig eth0 | sed -nr 's#^.*inet (.*) net.*$#\1#gp'
-nr 查找
s###g 替换
^.*inet 匹配inet及开头所有 (inet )
^ 以开头的所有
.*inet 匹配inet
(.*) 要截取的IP,做后项引用 (10.0.0.7)
net.*$ 匹配net及结尾所有 (netmask 255.255.255.0 broadcast 10.0.0.255)
net.* 匹配net
$ 以结尾的所有
\1 后项引用
p 打印
# 其他方法
ifconfig | sed -n '2p'|sed -nE 's/.*inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\1/p'
ifconfig eth0 | sed -n 's/.*inet \([^ ]*\).*/\1/p'
sed模式空间
`换行符\n
# 换行符替换成空格
[root@web01 ~]# sed 'N;s#\n# #g' 1.test
1,wy,666 2,hh,777
3,wb,888 4,zd,999
5,ms,000
# N;
[root@web01 ~]# sed 'N;N;N;N;s#\n# #g' 1.test
1,wy,666 2,hh,777 3,wb,888 4,zd,999 5,ms,000
`sed模式空间
# :label;N; ;t label
[root@web01 ~]# sed ':label;N;s#\n# #g;t label' 1.test
1,wy,666 2,hh,777 3,wb,888 4,zd,999 5,ms,000
awk
awk 不是一个命令,是一门语言,也能做for循环,awk有单双引之分
awk又叫GNU awk,gawk
[root@web01 ~]# which awk
/usr/bin/awk
[root@web01 ~]# ls -l `which awk`
lrwxrwxrwx. 1 root root 4 Apr 12 11:11 /usr/bin/awk -> gawk
'' 输出变量
"" 输出字符串
awk输出变量用单引 bash输出变量""
平时我们使用,都是当做命令使用,所以我们称之为 单行脚本 那么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执行流程
awk读取文件内容之前 1.读取文件之前,先看命令的选项,例如 -F,-v (F指定为分隔符,V是赋予变量) 2.如果写了BEGIN{}则先在BEGIN{}中的指令
awk读取文件内容之时 1.awk在读取文件时,也是一行一行的读 2.读取一行之后,判断是否满足条件,如果是,则执行{对应动作} {print $1} awk -F , {print $1} 1.txt 3.如果不满足条件,awk继续读取下一行,直到满足条件或者到文件的最后一行
awk读取文件内容之后 1.所有文件读取完成之后,走END{}中的指令
读取文件之前
BEGIN{}
读取文件时
{}
读取文件之后
NED{}
# 读取文件时{}
[root@web01 ~]# awk '{print 1+2}'
^C
[root@web01 ~]# awk '{print 1+2}' 1.test
3
3
3
3
3
# 读取文件之前BEGIN{}
[root@web01 ~]# awk 'BEGIN{print 1+2}'
3
# 读取文件之后END{}
[root@web01 ~]# awk 'END{print 1+2}'
^C
[root@web01 ~]# awk 'END{print 1+2}' 1.test
3
awk的行和列
行 记录 record
列 字段 field
awk的取行
取行——取记录
`NR
number of record
# 取第一行
NR==1
[root@web02 web02]# awk 'NR==1' /etc/passwd
root:x:0:0:root:/root:/bin/bash
# 取一到三行
[root@web02 web02]# awk 'NR==1,NR==3' /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@web01 ~]# awk 'NR<=3' /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
# sed 从第三行到最后一行
sed -n '3,$p'
# awk 从第三行到最后一行
[root@web02 web02]# awk 'NR>=3' /etc/passwd
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
………………
………………
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
`# awk的控制结束标语
awk -vRS= 是指定换行符
例: (以逗号为换行符: -vRS=,) (以点为换行符: vRS=.)
# 以,(逗号)为换行符 默认是以回车为分割符
[root@web02 web02]# cat 1.txt
1,wy,666
2.hh.777
3,wb,888
4.zd.999
5,ms,000
[root@web02 web02]# awk -vRS=, "NR==2" 1.txt
wy
[root@web02 web02]# awk -vRS=, "NR==3" 1.txt
666
2.hh.777
3
[root@web02 web02]# awk -vRS=, "NR==4" 1.txt
wb
[root@web02 web02]# awk -vRS=, "NR==5" 1.txt
888
4.zd.999
5
[root@web01 ~]# awk -vRS=, '{print "这里是行号:"NR,"这里是每一行的内容:"$0}' 1.test
这里是行号:1 这里是每一行的内容:1
这里是行号:2 这里是每一行的内容:wy
这里是行号:3 这里是每一行的内容:666
2
这里是行号:4 这里是每一行的内容:hh
这里是行号:5 这里是每一行的内容:777
3
这里是行号:6 这里是每一行的内容:wb
这里是行号:7 这里是每一行的内容:888
4
这里是行号:8 这里是每一行的内容:zd
这里是行号:9 这里是每一行的内容:999
5
这里是行号:10 这里是每一行的内容:ms
这里是行号:11 这里是每一行的内容:000
[root@web01 ~]# cat 1.test
1,wy,666
2,hh,777
3,wb,888
4,zd,999
5,ms,000
awk的取列
取列——取字段
-vFS=: <==> -F:
FS 列分隔符
$数字 或 $内容(多个用,隔开)
# 每一行有多少列 字段(列)
NF== $number of field
FS: 内置变量 列分隔符 -F: = -vFS=:
# 打印出第一列和最后一列
[root@web02 web02]# awk -vFS=: '{print $1,$NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown
halt /sbin/halt
mail /sbin/nologin
operator /sbin/nologin
# 用#隔开第一列与第二列与……与第五列
[root@web02 web02]# awk -F: '{print $1"#"$2"#"$3"#"$4"#"$5}' /etc/passwd
root#x#0#0#root
bin#x#1#1#bin
daemon#x#2#2#daemon
adm#x#3#4#adm
lp#x#4#7#lp
sync#x#5#0#sync
shutdown#x#6#0#shutdown
halt#x#7#0#halt
mail#x#8#12#mail
operator#x#11#0#operator
games#x#12#100#games
ftp#x#14#50#FTP User
# 修改输出后的内容分隔符
-vOFS=
-vOFS=#
[root@web01 ~]# awk -F: -vOFS=# '{print $1,$2,$3,$4,$5}' /etc/passwd
root#x#0#0#root
bin#x#1#1#bin
daemon#x#2#2#daemon
adm#x#3#4#adm
lp#x#4#7#lp
sync#x#5#0#sync
shutdown#x#6#0#shutdown
halt#x#7#0#halt
mail#x#8#12#mail
operator#x#11#0#operator
games#x#12#100#games
ftp#x#14#50#FTP User
nobody#x#99#99#Nobody
[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
[root@web01 ~]# awk -F: -vOFS=\& '{print $1,$2,$3,$4,$5}' /etc/passwd
root&x&0&0&root
bin&x&1&1&bin
daemon&x&2&2&daemon
adm&x&3&4&adm
lp&x&4&7&lp
sync&x&5&0&sync
shutdown&x&6&0&shutdown
halt&x&7&0&halt
mail&x&8&12&mail
operator&x&11&0&operator
games&x&12&100&games
ftp&x&14&50&FTP User
nobody&x&99&99&Nobody
截取top时间/截取IP
[root@web01 ~]# top
top - 10:15:05 up 1:40, 2 users, load average: 0.06, 0.03, 0.05
Tasks: 91 total, 2 running, 89 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 995892 total, 742740 free, 124532 used, 128620 buff/cache
KiB Swap: 1048572 total, 1048572 free, 0 used. 719416 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 125288 3728 2568 S 0.0 0.4 0:01.70 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.24 ksoftirqd/0
19 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset
20 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset
top -n1 是让他停止跳动
## 截取top时间
top -n1 | awk 'NR==1{print $3}'
## 截取top的TIME+
[root@web02 web02]# top -n1 | awk 'NR>=7{print $12}'
TIME+
0:08.99
0:00.06
0:11.940:00.00
0:00.00
0:00.00
0:08.82
0:00.00
0:03.21
0:00.00
0:00.00
# 截取IP 匹配范围/IPADDR/
[root@web02 web02]# awk -F= '/IPADDR/{print $2}' /etc/sysconfig/networkscripts/ifcfg-eth0 | awk -F '"' '{print $2}'
10.0.0.8
[root@web02 ~]# awk -F'[= "]+' '/IPADDR/{print $2}' /etc/sysconfig/network-scripts/ifcfg-eth0
10.0.0.8
一个完整的awk
#一个完整的awk
[root@web01 ~]# awk -F: 'BEGIN{print "name","uid"}{print $1,$3}END{print "文件处理完成"}' /etc/passwd |column -t
name uid
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-network 192
dbus 81
polkitd 999
sshd 74
postfix 89
ntp 38
nginx 998
xxx 1000
文件处理完成
## 解析
-F : 以:为分隔符
BEGIN{print "name","uid"} 读取文件之前,先打印出name 和 uid
{print $1,$3} 读取文件时打印出文件的第一列和第三列
END{print "文件处理完成"} 读取文件之后打印‘件处理完成’
column -t 为了美观对齐
awk的模式与动作
模式
在awk中到底有哪些可以被看做是模式的呢?
- 正则表达式
# 正则表达式写法
'/正则表达式/flag'
'$1~/正则表达式/flag'
'$1!~/正则表达式/flag'
只不过我们在awk中很少使用flag
- 比较表达式
NR==1
NR>=10
NR<=100
NR>=1 && NR<=10
$1>=100
- 范围模式
## 精确匹配行号:从第10行到第20行
NR==10,NR==20 (NR>=10&&NR<=20)
## 精确匹配字符串:从该字符串的行到另一个字符串所在行
'/root/,/wxk/'
'/从哪个字符串所在行/,/到那个字符串所在行/' #中间的行都包含进去
## 模糊匹配字符串:从含有该字符串所在行到含有另一字符串所在行
'$1~/oo/,$1~//
动作
动作 在awk中,我们最常用的动作就是 print 当然我们还有别的动作可以使用: print打印 gsub替换 变量赋值 统计计算 BEGIN模式 如果要使用BEGIN模式,那么一定要成双成对的出现:{} 那么我们要知道,BEGIN{}中,大括号里面的内容,会在读取文件内容之前执行 主要应用场景:
- 1.统计或计算
[root@zabbix01 ~]# awk 'BEGIN{print 1/3}'
0.333333
- 2.awk功能测试
- 3.输出表格的表头
END模式 一般来说,END{}要比BEGIN{}重要一些,BEGIN{}可有可无,计算其实可以放在读取文件的时候,也可以执行 END{}中,大括号里面的内容,会在awk读取完文件的最后一行后,进行处理 作用:一般我们使用END{}来显示对日志内容分析后的一个结果 当然,还有其他功能,比如文件读取完了,可以显示一些尾部信息
# 1.统计/etc/service文件中一共有多少行
## 分析:
## 条件:无
## 动作:读一行就加1 {i++}
[root@zabbix01 ~]# awk '{i++;print i}' /etc/services
#这么写是读一行会加一次,读一行会加一次,把整个过程都显示出来了。#我么现在只需要显示一个结果,所以我们需要把print放到END{}中
## 传统写法
[root@zabbix01 ~]# awk '{i++}END{print i}' /etc/services
11176
## 流氓写法
[root@zabbix01 ~]# sed -n '$=' /etc/services
11176
# 2.统计/etc/service中空行的数量
[root@zabbix01 ~]# awk '/^$/{i++}END{print i}' /etc/services
17
# 3.统计出下列文件中所有人的年龄和
[root@zabbix01 ~]# vim student.txt
姓名 年龄
呜呜呜 23
咕咕咕 18
嘿嘿嘿 99
[root@zabbix01 ~]# awk 'NR>1{i=i+$2}END{print i}' student.txt
140
[root@zabbix01 ~]# awk 'NR>1{i+=$2}END{print i}' student.txt
140
# 4.统计nginx日志中,状态码是200的次数以及,状态码是200时占用的流量
条件:
- 获取状态码 $9
- 获取大小 /流量 $10
## 获取条件
awk '$10==200' blog.aaa.com_access.log
## 执行动作
awk '$10==200{i++;count=count+$11}END{print i,count}'
blog.aaa.com_access.log
848 112743579
# 美化
awk '$10==200{i++;count=count+$11}END{print "正常状态码次数:"i,"总流量(字节):"count}'
blog.aaa.com_access.log
正常状态码次数:848 总流量(字节):112743579
## 脚本写法
awk '
$10==200{
i++;
count=count+$11
} E
ND{
print "正常状态码次数:"i,"总流量(字节):"count
}' blog.aaa.c_access.log
# 5.统计nginx日志中状态码是4xx和5xx的次数及总流量
条件:以4,5开头
动作:统计总流量
awk '$10~/^[45]/{i++;count+=$11}END{print i,count}'
blog.aaa.com_access.log
## 那么2xx的3xx的
awk '$10~/^2/{i++;count+=$11}END{print i,count}' blog.aaa.com_access.log
awk '$10~/^3/{i++;count+=$11}END{print i,count}' blog.aaa.com_access.log
# 6.综合应用:分别统计每种状态码的总流量
## 最简单的写法
awk '
$10~/^2/{i2++;count2+=$11}
$10~/^3/{i3++;count3+=$11}
$10~/^4/{i4++;count4+=$11}
$10~/^5/{i5++;count5+=$11}
END{
print "2xx状态码:",i2,count2
print "3xx状态码:",i3,count3
print "4xx状态码:",i4,count4
print "5xx状态码:",i5,count5
}' blog.aaa.com_access.log
### 注意:这种方式并不好,所以我们需要使用awk更牛的方法来统计不同分类的,比如统计IP,统计URI就没有
数组
赋值
awk 'BEGIN{array[0]="wyd";array[1]='hhh'}'
取值
awk 'BEGIN{array[0]="wyd";array[1]="hhh";print array[0],array[1]}'
会出来0和1 加个array[name]就会出来wyd和hhh
数组
# 会出来0和1 加个array[name]就会出来w和hh
[root@web02 web02]# awk 'BEGIN{array[0]="w0d";array[1]="l2f";for(name in array){print name}}'
0 1
[root@web02 web02]# awk 'BEGIN{array[0]="w0d";array[1]="l2f";for(name in array){print array[name]}}'
w0d
l2f
#1.取出下列域名并根据域名,进行统计排序处理
https://blog.aaa.com/index.html
https://blog.aaa.com/1.html
http://post.aaa.com/index.html
http://mp3.aaa.com/index.html
https://blog.aaa.com/3.html
http://post.aaa.com/2.html
## 在awk中,我们给数组赋值,肯定不能像上面那样赋值
#正确赋值方式:
array[]++
# 让数组的下标自增,然后在中括号中写入要统计的内容
array[域名所在列]++
array[$3]++ #当然这个$3是以/为分隔符
[root@zabbix01 ~]# awk -F/ '{url[$3]++}END{for(n in url){print n,url[n]}}'
url.txt
blog.aaa.com 3
post.aaa.com 2
mp3.aaa.com 1
#2.统计nginx日志中,每个IP访问使用的流量总和
条件:无
动作:统计IP及流量总和 array[$1]=array[$1]+$11 可以写成ip[$1]+=$11
awk '{array[$1]+=$11}END{for(ip in array){print ip,array[ip]}}'
blog.aaa.com_access.log
#3.每个IP出现的次数及使用的流量
条件:无
动作:
1.统计ip的次数:count[$1]++
2.流量总和:sum[$1]+=$11
awk '{count[$1]++;num[$1]+=$11}END{for(ip in count){print
ip,count[ip],num[ip]}}' blog.aaa.com_access.log
awk判断-if
#1.单分支判断
if($1~/root/){
print $1,$2
}
#2.双分支判断
if(){
}else{
}
if(){
}else if(){
}else{
}
awk循环-for
#数组专用循环
for(n in array){
print n,array[n]
}
#通用循环
for(i=1;i<10;i++){
print i
}