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 的基本概念:

  1. 记录(Record):awk 将输入数据视为一系列记录。默认情况下,记录是由换行符分隔的行
  2. 字段(Field):每个记录由字段组成。默认情况下,字段是由空格或制表符分隔的。字段可以通过 \$1, \$2, \$3, ... 来访问
  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

总结:

  1. BEGIN{ }  行前处理,读取文件内容前执行,指令执行1次
  2. { }             逐行处理,读取文件过程中执行,指令执行n次
  3. 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:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解

  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值