Linux云计算 |【第二阶段】SHELL-DAY5
主要内容:
awk命令、内置变量(FS、$0、$1、$2、NF、NR)、过滤时机(BEGIN{}、{}、END{})、处理条件(正则、&&、||、~\!~、==等)、awk数组、监控脚本、安全检测脚本
一、awk介绍
awk 是一种强大的文本处理工具,广泛用于 Unix 和 Linux 系统中。它是一种编程语言,专门用于处理结构化数据和生成格式化的报告。awk 的名字来源于其三位开发者 Alfred Aho、Peter Weinberger 和 Brian Kernighan 的姓氏首字母。
作用:基于模式匹配检查输入文本,逐行处理并输出;通常用在Shell脚本中,获取指定的数据;单独使用时,可对文本数据做统计;(精确搜索、数据统计)
补充:awk过滤数据时支持仅打印某一列;
补充:处理文本时,若未指定分隔符,则默认将空格、Tab制表符等作为分隔符。
1、awk 基本用法
格式:awk 'pattern { action }' file
- pattern:用于匹配输入行的条件。如果省略,
awk
将对所有行执行action
。- action:在匹配的行上执行的操作。
- file:要处理的文件。如果省略,
awk
将从标准输入读取数据。
常用 action 指令:
- {print} 输出
补充:使用awk时,如果指令就是{print},且前面写了条件的情况下可以省略{print}
awk 的基本概念:
- 记录(Record):awk 将输入数据视为一系列记录。默认情况下,记录是由换行符分隔的行
- 字段(Field):每个记录由字段组成。默认情况下,字段是由空格或制表符分隔的。字段可以通过 \$1, \$2, \$3, ... 来访问
- 变量:awk 有许多内置变量,例如 NF(字段数)、NR(记录数)、FS(字段分隔符)等
2、awk 内置变量
说明:
\$0
:文本当前行的全部内容(整行)\$1
,\$2
, ...:当前记录的第 1 个、第 2 个字段等(第1列、第2列,依此类推)NF
:当前记录中的字段数(有几列)NR
:当前记录的行号(类似sed中的"=")FS
:字段分隔符(默认是空格或制表符)RS
:记录分隔符(默认是换行符)OFS
:输出字段分隔符(默认是空格)ORS
:输出记录分隔符(默认是换行符)
3、awk 常见用法
1)特定字段打印
打印文件 file.txt 中每一行的第一个和第三个字段
awk '{ print \$1, \$3 }' file.txt
2)使用模式匹配
打印文件 file.txt 中包含 pattern 的行
awk '/pattern/ { print \$0 }' file.txt
3)计算字段的总和
计算文件 file.txt 中第一个字段的总和,并在处理完所有行后打印总和
awk '{ sum += \$1 } END { print sum }' file.txt
4)使用自定义字段分隔符
使用冒号 : 作为字段分隔符,并打印 /etc/passwd 文件中每一行的第一个字段。
awk -F':' '{ print \$1 }' /etc/passwd
5)使用变量
打印文件 file.txt 中每一行的第一个字段,并在前面加上变量 var 的值。
awk -v var="Hello" '{ print var, \$1 }' file.txt
4、awk 常用选项
-F fs
- 说明:指定输入字段分隔符(Field Separator)。
- 示例:awk -F':' '{ print \$1 }' /etc/passwd
- 解释:使用冒号 : 作为字段分隔符,并打印 /etc/passwd 文件中每一行的第一个字段。
-v var=value
- 说明:定义一个变量并赋值。
- 示例:awk -v var="Hello" '{ print var, \$1 }' file.txt
- 解释:定义变量 var 并赋值为 "Hello",然后打印文件 file.txt 中每一行的第一个字段,并在前面加上变量 var 的值。
-f scriptfile
- 说明:从指定的脚本文件中读取 awk 命令。
- 示例:awk -f script.awk file.txt
- 解释:从 script.awk 文件中读取 awk 命令,并应用于 file.txt 文件。
-v OFS=output_field_separator
- 说明:指定输出字段分隔符(Output Field Separator)。
- 示例:awk -v OFS="," '{ print \$1, \$2, \$3 }' file.txt
- 解释:使用逗号 , 作为输出字段分隔符,并打印文件 file.txt 中每一行的前三个字段。
-v ORS=output_record_separator
- 说明:指定输出记录分隔符(Output Record Separator)。
- 示例:awk -v ORS="\n\n" '{ print \$0 }' file.txt
- 解释:使用两个换行符 \n\n 作为输出记录分隔符,并打印文件 file.txt 中的每一行。
-v FS=input_field_separator
- 说明:指定输入字段分隔符(Field Separator)。
- 示例:awk -v FS="," '{ print \$1 }' file.csv
- 解释:使用逗号 , 作为输入字段分隔符,并打印文件 file.csv 中每一行的第一个字段。
-v RS=input_record_separator
- 说明:指定输入记录分隔符(Record Separator)。
- 示例:awk -v RS="\n\n" '{ print \$0 }' file.txt
- 解释:使用两个换行符 \n\n 作为输入记录分隔符,并打印文件 file.txt 中的每一行。
-v NF=number_of_fields
- 说明:指定每行的字段数。
- 示例:awk -v NF=3 '{ print \$1, \$2, \$3 }' file.txt
- 解释:指定每行有 3 个字段,并打印文件 file.txt 中每一行的前三个字段。
-v NR=number_of_records
- 说明:指定处理的记录数。
- 示例:awk -v NR=5 '{ print \$0 }' file.txt
- 解释:只处理文件 file.txt 中的前 5 行,并打印每一行。
awk变量练习示例1:
[root@svr7 ~]# cat test //测试文件
hello the world
welcome to beijing
例如:不加条件,输出所有
[root@svr7 opt]# awk '{print}' test
hello the world
welcome to beijing
例如:输出以h开头的行
[root@svr7 opt]# awk '/^h/{print}' test
hello the world
例如:输出所有行的第1列
[root@svr7 opt]# awk '{print $1}' test
hello
Welcome
例如:输出所有行的第1列和第3列
[root@svr7 opt]# awk '{print $1,$3}' test
hello world
welcome beijing
例如:输出以w开头,$0整行内容,第3列
[root@svr7 opt]# awk '/^w/{print $0,$3}' test
welcome to beijing beijing
例如:输出以w开头,$0整行内容,当前行的行号
[root@svr7 opt]# awk '/^w/{print $0,NR}' test
welcome to beijing 2
例如:输出以w开头,$0整行内容,当前行的列号
[root@svr7 opt]# awk '/^w/{print $0,NF}' test
welcome to beijing 3
例如:输出每行最后一个字段(列)
[root@svr7 ~]# awk -F: '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
例如:从脚本文件中读取 awk 命令
[root@svr7 opt]# awk -f script.awk example.csv
例如:使用逗号作为输出字段分隔符,并打印每一行的前两个字段
[root@svr7 opt]# awk -v OFS="," '{ print \$1, \$2 }' example.csv
例如:使用两个换行符作为输出记录分隔符,并打印每一行
[root@svr7 opt]# awk -v ORS="\n\n" '{ print \$0 }' example.csv
例如:输出passwd文件中以【:】分隔的第1、7个字段,需要显示的不同字段之间,以逗号【,】隔开( -F 可指定分隔符)
[root@svr7 opt]# awk -F: '/bash$/{print $1,$7}' /etc/passwd
root /bin/bash
student /bin/bash
lisi /bin/bash
...
通过“常量”显示字段之间的空白,增加辨识(awk的print指令不仅可以打印变量,还可以打印常量)
[root@svr7 opt]# awk -F: '/bash$/{print $1,"的解释器:"$7}' /etc/passwd
root 的解释器:/bin/bash
student 的解释器:/bin/bash
lisi 的解释器:/bin/bash
...
- 注意:输出“常量”时使用双引号【“”】
补充:awk输出特点,【,】显示为一个空格;直接打空格或多个空格,都不显示
[root@svr7 opt]# awk -F: '/bash$/{print $1 $7}' /etc/passwd
root/bin/bash
student/bin/bash
lisi/bin/bash
...
补充:awk可识别多种单个的字符,比如以“:”或“/”分隔,输出第1、10字段
[root@svr7 opt]# awk -F [:/] '{print $1,$10}' /etc/passwd
root bash
bin nologin
daemon nologin
...
awk变量练习示例1:
例如:输出/etc/hosts映射文件内以127或者192开头的记录
[root@svr7 ~]# awk '/^(127|192)/' /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
192.168.4.5 svr5.tarena.com svr5
例如:结合管道过滤命令输出根分区的磁盘剩余空间
[root@svr7 ~]# df -h /
文件系统 容量 已用 可用 已用% 挂载点
/dev/sda2 19G 7.2G 14G 40% /
[root@svr7 opt]# df -h / | tail -1 | awk '{print$4}'
14G
[root@svr7 opt]# df -h | awk '/\/$/{print$4}' //【/$】以根结尾,需加转义符【\】
14G
例如:检查登录失败的IP地址有哪些
[root@svr7 opt]# cat /var/log/secure
Apr 8 09:25:37 svr7 sshd[2497]: Failed password for root from 192.168.4.254 port 55446 ssh2
[root@svr7 opt]# awk '/Failed/{print $11}' /var/log/secure
192.168.4.254
例如:检查内存的剩余容量
[root@svr7 opt]# free
total used free shared buff/cache available
Mem: 1015292 397320 200064 7888 417908 410044
[root@svr7 opt]# free | awk '/Mem/{print"内存剩余容量"$4}'
内存剩余容量200216
例如:利用awk提取本机的网络流量
- 通过ifconfig eth0查看网卡信息,其中包括网卡流量:
[root@svr7 opt]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.4.7 netmask 255.255.255.0 broadcast 192.168.4.255
inet6 fe80::b7fc:281e:69b8:c18 prefixlen 64 scopeid 0x20<link>
ether 52:54:00:64:12:44 txqueuelen 1000 (Ethernet)
RX packets 21386 bytes 2395273 (2.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4196 bytes 508274 (496.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
RX为接收数据量,TX为发送数据量。packets以数据包数量为单位,bytes以字节为单位
- 过滤接收数据的流量
[root@svr7 opt]# ifconfig eth0 | awk '/RX p/{print"服务器eth0接收流量是"$5"字节"}' //过滤接收数据的流量
服务器eth0接收流量是2436341字节
- 过滤发送数据的流量
[root@svr7 opt]# ifconfig eth0 | awk '/TX p/{print"服务器eth0接收流量是"$5"字节"}' //过滤发送数据的流量
服务器eth0发送流量是548040字节
二、awk 过滤时机(BEGIN{}、逐行处理{}、END{})
在 awk 中,处理文本数据的过程可以分为三个主要阶段:BEGIN 块、逐行处理块{} 和 END 块。每个阶段都有其特定的用途和执行时机。以下是这三个阶段的详细说明:
1、BEGIN 块
- 执行时机:在读取任何输入记录之前执行。
- 用途:用于初始化变量、设置输入/输出字段分隔符、打印标题等。
- 语法:BEGIN { action }
awk 'BEGIN { FS=","; OFS="\t"; print "Name\tAge\tCity" } { print \$1, \$2, \$3 }' example.csv
解释:
BEGIN 块中设置了输入字段分隔符 FS 为逗号 ,,输出字段分隔符 OFS 为制表符 \t。
打印标题行 "Name\tAge\tCity"。
逐行处理块中打印每一行的字段。
2、逐行处理块
- 执行时机:在读取每一行输入记录时执行。
- 用途:用于处理每一行的数据,进行字段提取、条件判断、计算等操作。
- 语法:{ action }
awk '{ if (\$2 > 30) print \$1, \$2, \$3 }' example.csv
解释:
逐行处理块中检查每一行的第二个字段是否大于 30。
如果条件满足,则打印该行的第一个、第二个和第三个字段。
3、END 块
- 执行时机:在读取所有输入记录之后执行。
- 用途:用于输出汇总信息、计算总和、打印统计结果等。
- 语法:END { action }
awk 'BEGIN { FS=","; OFS="\t"; print "Name\tAge\tCity" } { sum += \$2 } END { print "Total Age:", sum }' example.csv
解释:
BEGIN 块中设置了输入字段分隔符 FS 为逗号 ,,输出字段分隔符 OFS 为制表符 \t。
打印标题行 "Name\tAge\tCity"。
逐行处理块中累加每一行的第二个字段(年龄)。
END 块中打印总年龄 "Total Age:" 和累加结果 sum
总结:
- BEGIN{ } 行前处理,读取文件内容前执行,指令执行1次
- { } 逐行处理,读取文件过程中执行,指令执行n次
- END{ } 行后处理,读取文件结束后执行,指令执行1次
例如:只做BEGIN{}预处理的时候,可以没有操作文件
[root@svr7 ~]# awk 'BEGIN{a=34;print a+12}'
46
[root@svr7 ~]# awk 'BEGIN{print "HELLOWORLD"}'
HELLOWORLD
[root@svr7 ~]# awk 'BEGIN{print x+1}' //x可以不定义,直接用,默认值位0
1
例如:只做END{}处理的时候,需要有操作文件(只输出处理结果)
[root@svr7 opt]# awk 'END{print "BYE"}' user
BYE
例如:
[root@svr7 opt]# awk 'BEGIN{print NR}{print}END{print NR}' user
0
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
5
[root@svr7 opt]# awk 'BEGIN{print NR}END{print NR}' user
0 //预处理时,行数为0
5 //当文本全部处理完之后执行,行数为已读入文本的行数
例如:统计系统中使用/bin/bash作为登录Shell的用户总个数
- 思路1:预处理时赋值变量x=0
- 思路2:然后逐行读入/etc/passwd文件,如果发现登录Shell是/bin/bash则x加1
- 思路3:全部处理完毕后,输出x的值即可
[root@svr7 opt]# awk 'BEGIN{x=0}/\/bin\/bash$/{x++}END{print x}' /etc/passwd
7
例如:格式化输出/etc/passwd文件,要求第一行为列表标题,中间打印用户的名称、UID、家目录信息,最后一行提示一共已处理文本的总行数,如图所示:
- 思路1:
[root@svr7 opt]# awk 'BEGIN{print"User\tUID\tHome"}'
User UID Home
【\t】显示Tab制表位,必须需写在双引号【“”】内才能生效
- 思路2:
[root@svr7 opt]# awk -F: '{print $1"\t"$3"\t"$6}' user
root 0 /root
bin 1 /bin
daemon 2 /sbin
adm 3 /var/adm
lp 4 /var/spool/lpd
- 思路3:
[root@svr7 opt]# awk 'END{print"Total: "NR,"lines."}' user
Total: 5 lines.
结果:
[root@svr7 opt]# awk -F: 'BEGIN{print"User\tUID\tHome"} {print$1"\t"$3"\t"$6} END{print"Total:",NR,"lines."}' user
User UID Home
root 0 /root
bin 1 /bin
daemon 2 /sbin
adm 3 /var/adm
lp 4 /var/spool/lpd
Total: 5 lines.
三、awk 处理条件
概述:所有的行全部处理并输出;限制处理的条件;根据多个条件来处理指定的行
回顾格式:awk [选项] ‘[条件] {指令}’ 被处理文件...
条件的表现形式:
- ① 正则表达式:/表达式/、~、!~
- ② 数值/字符串比较:==、!=、>、>=、
- ③ 逻辑比较:&& 逻辑与、||逻辑或
- ④ 运算符:+、-、*、/、%、++、--、+=、-=、*=、/=
1)正则表达式
- /正则表达式/
- ~包含、!~不包含
例如:输出其中以bash结尾的行
[root@svr7 opt]# awk -F: '/bash$/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
student:x:1000:1000:Student:/home/student:/bin/bash
...
例如:输出包含root的行
[root@svr7 opt]# awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
例如:输出root或adm账户的用户名和UID信息
[root@svr7 opt]# awk -F: '/^(root|adm)/{print $1,$3}' /etc/passwd =
root 0
adm 3
例如:~包含、!~不包含
[root@svr7 opt]# awk -F: '$1~/root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@svr7 opt]# awk -F: '$1~/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
补充:使用awk时如果指令就是{print},且前面写了条件的情况下可以省略{print}
例如:输出登录Shell不以nologin结尾(即对第7个字段做!~反向匹配)的用户名、登录Shell信息
[root@svr7 opt]# awk -F: '$7!~/nologin$/{print $1,$7}' /etc/passwd
root /bin/bash
sync /bin/sync
shutdown /sbin/shutdown
...
2)数值比较
- ==等于、!=不等于、>大于、>=大于或等于、
例如:输出第1行
[root@svr7 opt]# awk -F: 'NR==1' /etc/passwd
root:x:0:0:root:/root:/bin/bash
例如:输出第2行第7列
[root@svr7 opt]# awk -F: 'NR==2{print $7}' /etc/passwd
/sbin/nologin
例如:输出行号小于或等于3
[root@svr7 opt]# awk -F: '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
例如:输出账户UID大于等于1000的账户名称和UID信息(普通用户)
[root@svr7 opt]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
student 1000
lisi 1001
zhangsan 1002
...
例如:找解释器是/bin/bash的用户
[root@svr7 opt]# awk -F: '$7=="/bin/bash"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
student:x:1000:1000:Student:/home/student:/bin/bash
lisi:x:1001:1001::/home/lisi:/bin/bash
...
例如:找解释器不是/sbin/nologin的用户
[root@svr7 opt]# awk -F: '$7!="/sbin/nologin"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
...
例如:找解释器不是/sbin/nologin的用户及输出第1列包含root的行
[root@svr7 opt]# awk -F: '$1=="root"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@svr7 opt]# awk -F: '$1~/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
- 注意:==比~包含更严格匹配,~包含稍微宽松匹配
例如:查看包含2个及以上字段的行
[root@svr7 opt]# awk 'NF>=2{print}' /etc/passwd
3)逻辑比较
- && 逻辑与:期望多个条件多成立;
- || 逻辑或:只要有一个条件成立即满足要求;
例如:找uid范围是10~20的行
[root@svr7 opt]# awk -F: '$3>=10&&$3<=20' /etc/passwd
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
例如:找行号2~10行
[root@svr7 opt]# awk 'NR>=2&&NR<=10' /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
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
例如:找uid是0~4或者1001以上的行
[root@svr7 opt]# awk -F: '$3<5||$3>1001' /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
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
zhangsan:x:1002:1002::/home/zhangsan:/bin/bash
wangwu:x:1003:1003::/home/wangwu:/bin/bash
abc01:x:1004:1004::/home/abc01:/bin/bash
Tom:x:1005:1005::/home/Tom:/bin/bash
4)运算符
- +、-、*、/、%
- ++、--、+=、-=、*=、/=
例如:不定义x,默认为0
[root@svr7 opt]# awk 'BEGIN{x++;print x}'
1
[root@svr7 opt]# awk 'BEGIN{x=8;print x+=2}'
10
[root@svr7 opt]# awk 'BEGIN{print x+=2}'
2
[root@svr7 opt]# awk 'BEGIN{print 2*2}'
4
[root@svr7 opt]# awk 'BEGIN{print 10%3}'
1
例如:显示偶数行
[root@svr7 opt]# awk 'NR%2==0' user
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
例如:显示奇数行
[root@svr7 opt]# awk 'NR%2==1' user
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
例如:统计文本的总字段个数
[root@svr7 opt]# awk 'BEGIN{i=0}{i+=NF}END{print i}' user
5
四、awk 数组
1)定义数组
格式:数组名[下标]=元素值 //数组名[下标]=下标对应的值(类似变量)
解释:数组是一个可以存储多个值的变量;
2)调用数组
格式:数组名[下标]
3)遍历数组(awk命令使用数组和for循环实现高级搜索)
用法:for( 变量 in 数组名 ){print 数组名[变量]}
[root@svr7 /]# awk 'BEGIN{a=11;b=22;print a,b}' //变量
11 22
[root@svr7 /]# awk 'BEGIN{a[1]=10;a[2]=20;print a[1],a[2]}' //数组[下标]
10 20
解释:使用awk测试数组创建了一个数组名字叫a,分别定义两个下标与对应的两个值,然后用print查看了a[1]的值和a[2]的值;
例如:创建素材文件data,该文件里面有三行信息;
[root@svr7 ~]# cat data
abc
xyz
abc
使用逐行任务{a[$1]++}走完所有行的第1列得到:
1 abc -> a[abc]++ -> a[abc]=1
解释:起始a[abc]默认为0。匹配1次+1(0+1=1)
2 xyz -> a[xyz]++ -> a[xyz]=1
解释:起始a[xyz]默认为0。匹配1次+1(0+1=1)
3 abc -> a[abc]++ -> a[abc]=2
解释:a[abc]已匹配1次。再匹配1次+1(1+1=2)
{a[$1]++} 对文本的每行内容以第一个字段【$1】为数组下标进行计数。若遇第一个字段相同的情况,计数累加。
[root@svr7 ~]# awk '{a[$1]++}END{print a["abc"],a["xyz"]}' data
2 1
解释:根据上述结果,得到如果使用{a[$1]++}走完所有行,便可收集到a[xyz]=1和a[abc]=2的结果,所以在最后使用END任务输出a[“xyz”]和a[“abc”]的值就是 1和 2
[root@svr7 ~]# awk '{a[$1]++}END{for(i in a){print i}}' data
abc
xyz
[root@svr7 ~]# awk '{a[$1]++}END{for(i in a){print a[i]}}' data
2
1
[root@svr7 ~]# awk '{a[$1]++}END{for(i in a){print i,a[i]}}' data
abc 2
xyz 1
解释:使用for循环,循环显示数组a的下标,与值,其中for(i in a)里面的i是变量,代表下标,in是语法不能变,a是数组名
例如:
[root@svr7 ~]# awk 'BEGIN{a[0]=11;a[1]=88;print a[1],a[0]}'
88 11
[root@svr7 ~]# awk 'BEGIN{a++;print a}'
1
[root@svr7 ~]# awk 'BEGIN{a[0]++;print a[0]}' //”a[0]”相当于1个变量
1
[root@svr7 ~]# awk 'BEGIN{a[0]=0;a[1]=11;a[2]=22; for(i in a){print i,a[i]}}'
0 0
1 11
2 22
案例:针对Web访问日志计算访问量排名
思路分析:
① 获取关键词:客户机地址、访问次数
[root@svr7 /]# cd /var/log/httpd/ //Apache日志目录
[root@svr7 httpd]# ls
access_log error_log
[root@svr7 httpd]# wc -l access_log //access_log为登入httpd来访者的记录
4 access_log
[root@svr7 httpd]# tail -1 access_log
192.168.4.7 - - [08/Apr/2021:16:36:15 +0800] "GET /favicon.ico HTTP/1.1" 404 209 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"
- 关键词:access_log日志中第1个字段即对应客户机的IP
② 利用awk提取客户机IP地址、访问次数
[root@svr7 httpd]# awk '{print $1}' /var/log/httpd/access_log
192.168.4.7
192.168.4.7
192.168.4.7
192.168.4.7
③ 以$1作为下标,定义数组ip,【ip[$1]】
④ 利用for循环输出数组下标、对应数组元素的值
[root@svr7 httpd]# awk '{ip[$1]++}END{print ip["192.168.4.7"]}' /var/log/httpd/access_log
8
[root@svr7 httpd]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log
192.168.4.7 8
补充:利用sort可提取结果访问次数排名
[root@svr7 /]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log | sort -nr
192.168.4.7 8
补充:利用sort对提取结果排序
[-n] 按数字生序排列
[-k] 针对指定的列进行排序
[-r] 反向排序
案例:安全检测脚本(防止远程ssh暴力破解密码)
任务需求:统计登录服务器失败的用户IP记录,/var/log/secure是系统的安全日志,如果有人登录服务器而密码输入错误则会记录到该文档中;(测试前登录服务器并故意输入错误密码)
思路分析:
① ssh登录的安全日志为/var/log/secure
[root@svr7 ~]# ls /var/log/secure
/var/log/secure
[root@svr7 ~]# grep 'Failed' /var/log/secure
Apr 8 09:25:37 svr7 sshd[2497]: Failed password for root from 192.168.4.254 port 55446 ssh2
② 分析日志文件格式
Apr 8 09:25:37 svr7 sshd[2497]: Failed password for root from 192.168.4.254 port 55446 ssh2
- 关键词:Failed password 及 登录失败的IP(在记录中的第11列)
② 找出用户名以及密码错误的规律,并提取有数据
[root@svr7 ~]# awk '/Failed password/{print}' /var/log/secure
Apr 8 09:25:37 svr7 sshd[2497]: Failed password for root from 192.168.4.254 port 55446 ssh2
Apr 9 09:27:55 svr7 sshd[2649]: Failed password for root from 192.168.4.254 port 48504 ssh2
Apr 9 09:27:59 svr7 sshd[2649]: Failed password for root from 192.168.4.254 port 48504 ssh2
③ 对有效数据进行汇总统计,实现黑名单过滤动能
[root@svr7 ~]# awk '/Failed password/{ip[$11]++}END{for(i in ip){print i,ip[i]}}' /var/log/secure
192.168.4.254 3
[root@svr7 ~]# ls /var/log/ //安全日志文件
secuer-20210409 secure-20210312
案例:监控脚本
编写脚本监控本机各项数据指标:
- ① CPU负载:uptime、top
- ② 内存剩余容量:free,[-h]显示单位
- ③ 磁盘剩余容量:df,[-h]显示单位
- ④ 计算机账户数量:cat /etc/passwd | wc -l
- ⑤ 当前登录账户数量:who | wc -l
- ⑥ 当前开启的进程数量:ps -aux | wc -l
- ⑦ 网卡流量:ifconfig
- ⑧ 已安装的软件包数量:rpm -qa | wc -l
思路分析:
① 查看CPU负载、系统登录时间(或top)
[root@svr7 /]# uptime
10:13:12 up 1:39, 1 user, load average: 0.00, 0.01, 0.05
[root@svr7 /]# uptime | awk '{print $NF}'
0.05
- 关键词:15分钟平均负载($NF)
[root@svr7 /]# uptime | awk '{print "cpu15分钟平均负载量是:" $NF}'
cpu15分钟平均负载量是:0.05
② 查看内存容量
[root@svr7 /]# free -h
total used free shared buff/cache available
Mem: 991M 383M 178M 7.7M 429M 405M
Swap: 2.0G 0B 2.0G
[root@svr7 log]# free -h | awk '/^Mem/{print}'
Mem: 991M 384M 178M 7.7M 429M 404M
- 关键词:Mem内存,free剩余($4)
[root@svr7 /]# free -h | awk '/^Mem/{print "剩余内存容量是:"$4}'
剩余内存容量是:178M
③ 查看磁盘剩余容量
[root@svr7 /]# df -h
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/centos-root 17G 3.7G 14G 22% /
- 关键词:根分区,可用容量($4)
[root@svr7 /]# df -h | awk '/\/$/{print "服务器根分区剩余容量是:"$4}'
服务器根分区剩余容量是:14G
④ 计算机账户数量
[root@svr7 opt]# wc -l /etc/passwd
48 /etc/passwd
- 关键词:统计/etc/passwd记录行数($1)
方法1:
[root@svr7 opt]# wc -l /etc/passwd | awk '{print $1}'
48
方法2:
n=$(wc -l /etc/passwd) //定义变量
n1=${n%%/*} //去尾
echo "服务器账户总是:$n1个"
方法3:
[root@svr7 opt]# awk 'BEGIN{i=0}{i=NR}END{print i}' /etc/passwd
48
⑤ 当前登录账户数量
[root@svr7 opt]# who
root pts/0 2021-04-09 09:01 (192.168.4.254)
- 关键词:统计who记录行数
[root@svr7 opt]# echo $(who | wc -l)
1
⑥当前开启的进程数量
[root@svr7 opt]# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.6 128304 6848 ? Ss 08:33 0:01 /usr/lib/system
root 2 0.0 0.0 0 0 ? S 08:33 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 08:33 0:00 [ksoftirqd/0]
...
- 关键词:统计ps记录行数
[root@svr7 opt]# echo $(ps aux | wc -l)
180
编写脚本
[root@svr7 opt]# vim test.sh
#!/bin/bash
while :
do
clear //清空屏幕显示
uptime | awk '{print "cpu15分钟平均负载量是:" $NF}'
df -h | awk '/\/$/{print "服务器根分区剩余容量是:"$4}'
free -h | awk '/^Mem/{print "剩余内存容量是:"$4}'
n=$(wc -l /etc/passwd)
n1=${n%%/*}
echo "服务器账户总是:$n1个"
echo "当前登录账户数量是:$(who | wc -l)个"
x=$(ps aux | wc -l)
echo "当前开启的进程数量是:$x个"
sleep 3
done
测试:
[root@svr7 opt]# bash test.sh
cpu15分钟平均负载量是:0.05
服务器根分区剩余容量是:14G
剩余内存容量是:174M
服务器账户总是:48 个
当前登录账户数量是:2个
当前开启的进程数量是:183个
扩展知识:
awk 和 sed 都是 Unix 和 Linux 系统中常用的文本处理工具,但它们的设计目的和使用场景有所不同。以下是它们的主要区别:
1、awk:(更适合处理结构化数据和生成报告,支持复杂的文本处理任务)
设计目的:awk 是一种编程语言,专门用于处理结构化数据和生成格式化的报告。它主要用于数据提取和报告生成,适合处理包含字段的文本文件(如 CSV 文件)。awk 提供了丰富的内置变量和函数,支持条件判断、循环、数组等高级功能。
语法和功能:
- 语法:awk 'pattern { action }' file
- 支持字段操作:\$1, \$2, \$3, ...
- 支持内置变量:NF(字段数)、NR(记录数)、FS(字段分隔符)等
- 支持条件判断、循环、数组等高级功能
- 适合处理结构化数据和生成报告
# 打印文件中每一行的第一个和第三个字段
awk '{ print \$1, \$3 }' file.txt
# 计算文件中第一个字段的总和
awk '{ sum += \$1 } END { print sum }' file.txt
# 打印包含特定模式的行
awk '/pattern/ { print \$0 }' file.txt
2、sed:(更适合简单的文本编辑和转换任务,适合处理单行文本或简单的多行文本)
设计目的:sed 是一种流编辑器,主要用于对文本进行基本的编辑操作,如替换、删除、插入等。它适合用于简单的文本转换和处理任务,如批量替换文件中的字符串。sed 的语法相对简单,主要通过命令和正则表达式来操作文本。
语法和功能:
- 语法:sed 's/pattern/replacement/' file
- 支持基本的文本编辑操作:替换(s)、删除(d)、插入(i)、追加(a)等
- 支持正则表达式
- 适合简单的文本转换和处理任务
# 替换文件中的字符串
sed 's/old/new/g' file.txt
# 删除包含特定模式的行
sed '/pattern/d' file.txt
# 在每行前插入一行
sed 'i\Inserted line' file.txt
思维导图:
小结:
本篇章节为【第二阶段】SHELL-DAY5 的学习笔记,这篇笔记可以初步了解到 awk命令、内置变量、过滤时机、处理条件、awk数组、监控脚本、安全检测脚本
Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解