Shell阶段10 awk工作原理, 内部变量, 正则/比较/条件/逻辑表达式, 判断语句, 循环语句, awk数组

AWK

什么是awk
awk是一个编程语言
主要作用: 对文本和数据的处理

awk处理数据的流程
1.扫描文件内容,从上到下进行扫描,按照行进行处理
2.寻找匹配到的内容,进行读取到特定的模式中,进行行处理
3.行满足指定模式动作,则输出到屏幕上面,不满足丢弃
4.接着读取下一行继续处理,接着循环,直到文件的结尾

awk语法格式
awk [选项] command files
awk '[pattern]{COMMAND}' file
pattern 可以没有,默认每一个
{COMMAND} 也可以为空,默认 print $0
但是 pattern 和 {COMMAND} 不能同时为空

三种格式
行处理前        行处理中        行处理后
BEGIN            执行的命令       最后的显示 END

#行处理前
[root@shell01 ~]# awk 'BEGIN{print 1 + 1}'
2

#行处理前+行处理中  (-F是简写)
[root@shell01 ~]# awk -F: '{print $1}' /etc/passwd
root
bin
#-F为处理前,等于BEGIN{FS=':'}     {print $1}为行处理中
[root@shell01 ~]# awk 'BEGIN{FS=":"}{print $1}' /etc/passwd

#输出分隔符默认为空格,这里修改为#
[root@shell01 ~]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2}' /etc/passwd
root#x
bin#x
daemon#x

#行处理前+行处理中+行处理后    (END为行处理后,会在最后执行)
[root@shell01 ~]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2}END{print "内容打印结束"}' /etc/passwd
root#x
bin#x
...
内容打印结束

#行处理前+行处理中+行处理后 (文件有几行,就打印几行OK)
[root@shell01 ~]# awk 'BEGIN{print 1+1}{print "OK"}END{print "内容打印结束"}' /etc/hosts
2
OK
OK
内容打印结束

[root@shell01 ~]# cat test.txt 
10 10 10
[root@shell01 ~]# awk '{print $1+$2}' test.txt
20

[root@shell01 ~]# awk -F: '{print $1,$3}' /etc/passwd
root 0
bin 1


awk的工作原理
1.awk将文件中的每一行作为输入,将每一行的数据赋值给内部变量    $0
2.awk开始进行字段分解,根据指定的分隔符,将每个字段进行赋值给内部变量 $1 $2 $3
3.awk默认的分隔为空白字符,由内部变量FS来确定,也可以使用-F进行指定对应的分隔符
4.awk处理时使用print进行打印已分隔后的字段
5.awk打印输出结果之后,不同字段之间由空格进行分隔,这个空格是由不同字段之间的逗号进行映射的,由内部变量OFS进行修改,OFS默认的输出分隔符就是空格
6.awk输出一行内容后,重新读取下一行内容,会覆盖内部变量$0,然后新的字符进行字段分割并进行处理。

#awk的命令格式
    匹配    模式    动作

#匹配 模式(root就是模式)
[root@shell01 shell13]# awk '/root/' passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

#动作
[root@shell01 shell13]# awk '{print $1}' passwd 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

#模式+动作
[root@shell01 shell13]# awk -F: '/root/{print $1}' passwd 
root
operator

#当根分区使用率大于多少则打印Available
[root@shell01 shell13]# df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda3       18863104 1875848  16987256  10% /
devtmpfs          487048       0    487048   0% /dev
[root@shell01 ~]# df |awk '/\/$/{print $4}'
16987256
[root@shell01 ~]# df |awk '/\/$/{ if ($3>180000)  print $4}'
16987256

Awk的内部变量

1. 输入分隔符
FS        输入分隔符    默认以空白字符为分隔符

[root@shell01 ~]# awk -F: '{print $1}' passwd
[root@shell01 ~]# awk 'BEGIN{FS=":"}{print $1}' passwd
#指定多个分隔符, :和空格
[root@shell01 ~]# awk -F '[ :]' '{print $3}' passwd

#获取ip地址
[root@shell01 shell13]# ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:49:ee:cc brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.2/24 brd 10.0.0.255 scope global noprefixroute eth0
#注意:行开头空格前面也算一个字符;如果碰到' /'空格和斜杠一起,算一个分割符
[root@shell01 ~]# ip a s eth0|awk -F '[ /]*' 'NR==3{print $3}' 

2. 输出分隔符
OFS        默认输出分隔为空格,    打印的时候用逗号作为分割,逗号就是输出分隔符,在显示的时候,默认映射为空格。

[root@shell01 shell13]# awk -F: '{print $1,$2}' passwd 
root x
bin x
[root@shell01 shell13]# awk -F: '{print $1$2}' passwd 
rootx
binx
#-v指定内部变量,分隔符为@
[root@shell01 shell13]# awk -F: -vOFS="@" '{print $1,$2}' passwd 
root@x
bin@x
[root@shell01 shell13]# awk -F: 'BEGIN{OFS="$"}{print $1,$2}' passwd 
root@x
bin@x

3. 内部变量NF    最后一列

# NF    表示每一行最后一列(列数)        $NF    打印最后一列的内容
[root@shell01 shell13]# awk -F: '{print $NF}' passwd 
/bin/bash
/sbin/nologin
/sbin/nologin
[root@shell01 shell13]# awk -F: '{print NF}' passwd 
7
7


4. 内部变量$0
$0 表示整行内容

#没有过滤,打印所有内容
[root@shell01 shell13]# awk '{print $0}' 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@shell01 shell13]# awk 'NR==1{print $0}' passwd
root:x:0:0:root:/root:/bin/bas


5. 内部变量NR
NR    表示是行号    $NR不可用

#NR显示行号
[root@shell01 shell13]# awk '{print NR,$0}' passwd 
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

#第一行
[root@shell01 shell13]# awk 'NR==1' passwd 
root:x:0:0:root:/root:/bin/bash
[root@shell01 shell13]# awk 'NR==1{print $0}' passwd 
root:x:0:0:root:/root:/bin/bash

6. 内部变量    FNR
#FNR    显示行号,针对多个文件时进行处理
        不同的文件显示各自的行号
        
#下面两个文件行号叠加了,没有区分
[root@shell01 shell13]# awk '{print NR,$0}' passwd test.txt
1 root:x:0:0:root:/root:/bin/bas
...
10 2: eth0: <BROADCASE,MU...
#下面两个文件行号各区计算
[root@shell01 shell13]# awk '{print FNR,$0}' passwd test.txt
1 root:x:0:0:root:/root:/bin/bas
...
1 2: eth0: <BROADCASE,MU...


#了解
#7. RS 输入记录分隔符    ORS 输出记录分隔符

8. awk格式化输出

[root@shell01 ~]# date |awk '{print "今年是: "$NF"年","今月为: "$2"月"}'
今年是: 2024年 今月为: Jun月
[root@shell01 ~]# awk -F: '{print "用户为: "$1,"UID为:"$3,"GID为: "$4}' /etc/passwd
用户为: root UID为:0 GID为: 0
用户为: bin UID为:1 GID为: 1
用户为: daemon UID为:2 GID为: 2

printf 函数输出(了解)
%表示内容  -表示左对齐   20表示占20个字符   s表示字符类型
[root@shell01 ~]# awk -F: '{printf "%-20s %-10s %-10s\n", "用户为: "$1,"UID为:"$3,"GID为: "$4}' /etc/passwd
用户为: root            UID为:0     GID为: 0   
用户为: bin             UID为:1     GID为: 1   
用户为: daemon          UID为:2     GID为: 2 

Awk模式动作

1. 正则表达式

#获取root开头的
[root@shell01 ~]# awk '/^root/' /etc/passwd
#获取每一行等于root开头的,和上面效果相同,~表示等于
[root@shell01 ~]# awk '$0 ~/^root/' /etc/passwd
#获取第4列以root开头的
[root@shell01 ~]# awk -F: '$4 ~/^root/' /etc/passwd

#取反,不以root开头
[root@shell01 ~]# awk '!/^root/' /etc/passwd
[root@shell01 ~]# awk '$0 !~/^root/' /etc/passwd
#不取第4列以root开头的
[root@shell01 ~]# awk -F: '$4 !~/^root/' /etc/passwd

2. 比较表达式

关系运算符
<        小于
<=        小于等于
==        等于
>        大于
>=        大于等于
!=        不等于

[root@shell01 shell13]# awk -F: '$3==0' passwd
root:x:0:0:root:/root:/bin/bash
#下面{print $0}可以省略,默认打印该行
[root@shell01 shell13]# awk -F: '$5<0{print $0}' passwd

#字符串比较 (字符串最好用引号引起来)
[root@shell01 shell13]# awk -F: '$1=="root"' passwd 
root:x:0:0:root:/root:/bin/bash
#不等于
[root@shell01 shell13]# awk -F: '$4 != "root"' passwd 
 
[root@shell01 ~]# df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda3       18863104 1875848  16987256  10% /
devtmpfs          487048       0    487048   0% /dev
[root@shell01 ~]# df |awk '/\/$/'|awk '$3 > 1800000{print $4}'
16987148

3. 条件表达式

#如果第3列大于2万就打印整行
[root@shell01 ~]# awk -F: '{if($3>20000)print $0}' /etc/passwd
#每一行第3列大于1000打印最后一列,否则打印第一列
[root@shell01 ~]# awk -F: '{if($3>1000){print $NF} else {print $1}}' /etc/passwd

4. 运算表达式

[root@shell01 ~]# awk -F: '$3 * 100 > 50000' /etc/passwd
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
#如果$3乘以10大于1000打印最后一列,否则打印第一列
[root@shell01 ~]# awk -F: '{if($3*10>1000){print $NF} else {print $1}}' /etc/passwd
root
bin

[root@shell01 shell13]# awk -F: '/sync/{print $3}' passwd
5
[root@shell01 shell13]# awk -F: '/sync/{print $3 + 10}' passwd
15
[root@shell01 shell13]# awk -F: '/sync/{print $3*2}' passwd
10
[root@shell01 shell13]# awk -F: '/sync/{print $3/5}' passwd
1
[root@shell01 shell13]# awk -F: '/sync/{print $3^5}' passwd
3125
[root@shell01 shell13]# awk -F: '/sync/{print $3%5}' passwd
0
[root@shell01 shell13]# awk -F: '/sync/{print $3,$4}' passwd
5 0
[root@shell01 shell13]# awk -F: '/sync/{print $3+$4}' passwd
5

5. 逻辑操作符
&&        并且
||        或者
!        非

#行数大于2并且行数小于4
[root@shell01 shell13]# awk 'NR>2 && NR<4' passwd 
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@shell01 shell13]# awk 'NR>2 || NR<4' 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
#不为1的行
[root@shell01 shell13]# awk 'NR!=1' passwd 
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
#第1列为root且第三列大于10
[root@shell01 shell13]# awk -F: '$1 ~/root/ && $3 > 10' passwd
#不以root开头
[root@shell01 shell13]# awk '!/^root/' passwd

Awk判断语句

if

#1.打印系统管理员用户的数量
[root@shell01 ~]# awk -F: '$3==0' /etc/passwd |wc -l
#通过判断第三列是否为零,i进行累计,最后输出i
[root@shell01 ~]# awk -F: '{if($3==0){i++}}END{print "当前系统管理员用户的数量:"i}' /etc/passwd
当前系统管理员用户的数量:1

if    else

#打印系统管理员的数量和其他用户的数量
[root@shell01 ~]# awk -F: '{if($3==0){i++}else{j++}}END{print "当前系统管理员用户数量:"i,"当前系统其他用户数量:"j}' /etc/passwd
当前系统管理员用户数量:1 当前系统其他用户数量:23
#这里END中写两条print命令,用;隔开
[root@shell01 ~]# awk -F: '{if($3==0){i++}else{j++}}END{print "当前系统管理员用户数量:"i;print "当前系统其他用户数量:"j}' /etc/passwd
当前系统管理员用户数量:1
当前系统其他用户数量:23

if    else    if    else

#打印系统管理员的数量和系统用户的数量及普通用户的数量 (小于1000系统用户,大于1000普通用户)
[root@shell01 ~]# awk -F: '{if($3==0){a++}else{if($3>0 && $3<1000){b++}else{c++}}}END{print "管理员数量:"a,"系统用户数量:"b,"普通用户数量:"c}' /etc/passwd
管理员数量:1 系统用户数量:22 普通用户数量:1

Awk循环语句

while循环
[root@shell01 shell13]# awk 'BEGIN{ i=1; while(i<=3){print i; i++}}'
1
2
3

#相当于每一行,都要循环到总列数,并打印1-列数
[root@shell01 ~]# awk -F: '{i=1; while(i<=NF){print i;i++}}' /etc/passwd

#每一行都打印10次
[root@shell01 ~]# awk -F: '{i=1; while(i<=10){print $0;i++}}' /etc/passwd

for循环
#把每行所有内容一个个打印出来
[root@shell01 shell13]# awk -F: '{for(i=1;i<=NF;i++){print $i}}' passwd

awk数组

将需要统计的某个字段作为数组的索引,然后对索引进行遍历

#统计数组 (把最后一列作为索引)
[root@shell01 ~]# awk -F: '{shell[$NF]++}' /etc/passwd
#计算次数
[root@shell01 ~]# awk -F: '{shell[$NF]++}END{for(i in shell)print i"出现了"shell[i]"次"}' /etc/passwd
/bin/sync出现了1次
/bin/bash出现了1次
/sbin/nologin出现了20次
/sbin/halt出现了1次
/sbin/shutdown出现了1次

#站访问状态统计
[root@shell01 shell13]# ss -an
Netid State      Recv-Q Send-Q     Local Address:Port                    Peer Address:Port           
nl    UNCONN     0      0                      0:0                                   *
nl    UNCONN     0      0                      0:5717                                *
nl    UNCONN     0      0                      0:5717                                *
nl    UNCONN     4352   0                      4:7971                                *
[root@shell01 ~]# ss -an|awk '{status[$2]++}END{for(i in status)print i,status[i]}'
LISTEN 38
ESTAB 90
State 1
UNCONN 63

 

posted @ 2024-06-02 22:41  战斗小人  阅读(50)  评论(0编辑  收藏  举报