shell实战正则三贱客——awk

发布时间 2023-12-15 14:24:30作者: WeChat2834
shell实战正则三贱客——awk

特点及应用场景

awk
一门语言类似于c语言
过滤,统计,计算
过滤,统计,日志

执行过程

awk -F,  'BEGIN{print "name"}{print $2}END{print "end of file"}' oldboy.txt

image-20231208151702829

执行过程说明

  • awk读取文件之前
    1. 命令复制或命令行参数 (-F 或- v)
    2. BEGIN{} (执行里面的内容,里面的内容会在awk读取文件之前执行)
  • awk读取文件时(找谁干啥)
    1. 读取文件的一行
    2. 是否满足条件 :
      • 1)满足,则执行对应的动作 {print $2} 然后向下继续;
      • 2)不满足则向下继续
    3. 是否最后一行
      • 1)不满足则继续读取文件下一行
      • 2)满足 则向下继续
  • awk读取文件之后
    1. END{} (里面的内容会在awk读取文件之后执行显示结果)
    2. 结束

行与列

名词 说明
记录 record 每一行都是回车分割的
字段,域,field 每一列都是默认通过空格分隔的
awk中行和列结束标记(就是分隔符)都可以修改的

取行

awk
NR==1 取出某一行
NR>=1&&NR<=5 取出1到5行
/hellowrld/ 过滤(类似sed用法)
/101/,/105/
其他符号符号 > < >= <= == !=
[root@localhost awk]# awk NR==1 settst01.txt ####这儿因为没有{}也就每有执行动作
#1 2 3
[root@localhost awk]# 找谁 {干啥}
[root@localhost awk]# 条件 {动作}
[root@localhost awk]#
[root@localhost awk]# awk NR=/17/,/21/ settst01.txt           ####注意这只能是=不是==
#16 17 18
#
###
##19 20 21
[root@localhost awk]# awk '/5/' settst01.txt 
#4 5 #6
#13 14 15
#25 26 27
#34 35 36
#43 44 45
#49 50 51
#52 53 54
#55 56 57
#58 59 60
#64 65 66
#73 74 75
#85 86 87
#94 95 96
[root@localhost awk]# awk '/51/,/61/' settst01.txt 
#49 50 51
#52 53 54
#55 56 57
#58 59 60
#61 62 63
[root@localhost awk]# 

[root@localhost awk]# awk NR=/4/ settst01.txt                     ####感觉这样写也行,注意这只能是=不是==可能是因为匹配
#4 5 #6
#13 14 15
##22 23 24
#34 35 36
#40 41 42
#43 44 45
#46## 47 48
#49 50 51
#52 53 54
#64 65 66
#73 74 75
#82 83 84
#94 95 96
[root@localhost awk]# 
[root@localhost awk]# awk 'NR>=1&&NR<=5' settst01.txt 
#1 2 3
#4 5 #6
#7# 8 9
#
#
[root@localhost awk]# 

注意,写的时候最好都带上引号,神奇的一批

取列

参数

  • -F 指定分隔符 指定每一列结束标记(默认是空格,连续的空格,tab键),如果多个分隔符用双引号加上注意-F是支持正则和扩展正则的哈
  • $数字 取出某一列
  • $0 表示整行
  • $NF 表示最后一列
[root@localhost awk]# ls -l ../|awk  '{print $5}'

253
0
0
0
24
36
27
................
[root@localhost awk]# ls -l ../|awk  'NR==2 {print $0}'
-rw-r--r--. 1 root root   253 9月   5 15:48 !
[root@localhost awk]# 
[root@localhost awk]# ls -l ../|awk  'NR==2'
-rw-r--r--. 1 root root   253 9月   5 15:48 !
[root@localhost awk]# 
#####假如想看大小和文件名称
[root@localhost awk]# ls -l ../|awk  '{print $5,$9}'|column -t
253    !
0      10
0      11
0      12
24     array
........
[root@localhost awk]# column -t  让文本内容对齐

注意:column -t 让文本内容对齐

####取出password文件下的第一列和最后一列
[root@localhost awk]# awk -F ':'  '{print $1,$NF}' /etc/passwd |column -t
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
.......
####################注意,如果要在第一列和最后一列加分隔符,就有双引号替换逗号
[root@localhost awk]# awk -F ':'  '{print $1"@@@"$NF}' /etc/passwd |column -t
root@@@/bin/bash
bin@@@/sbin/nologin
daemon@@@/sbin/nologin
adm@@@/sbin/nologin
lp@@@/sbin/nologin
sync@@@/bin/sync
........
###############################
#########案例使用awk调换passwd 第1列和最后一列,第二列和倒数第二列...全部调换
[root@localhost awk]# awk -F ':'  '{print $NF":"$6":"$5":"$4":"$3":"$2":"$1}' /etc/passwd 
/bin/bash:/root:root:0:0:x:root
/sbin/nologin:/bin:bin:1:1:x:bin
/sbin/nologin:/sbin:daemon:2:2:x:daemon
/sbin/nologin:/var/adm:adm:4:3:x:adm
/sbin/nologin:/var/spool/lpd:lp:7:4:x:lp
.........
[root@localhost awk]# head -5 /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

awk内置变量

内置变量
NR Number of Record记录号,行号
NF Number of Field 每行有多个字段,$NF表示最后一列
FS -F: == -v FS=: Field Separator 字段分隔符,每个字段结束的标记
OFS Output Field Separator 输出字段分隔符(awk显示每一列的时候,每一列之间通过什么分隔,默认是空格)
-vOFS=: 输出以:分隔
[root@localhost awk]# awk -F:  -vOFS=:  '{print $NF,$6,$5,$4,$3,$2,$1}' /etc/passwd 
/bin/bash:/root:root:0:0:x:root
/sbin/nologin:/bin:bin:1:1:x:bin
/sbin/nologin:/sbin:daemon:2:2:x:daemon
/sbin/nologin:/var/adm:adm:4:3:x:adm
/sbin/nologin:/var/spool/lpd:lp:7:4:x:lp
/bin/sync:/sbin:sync:0:5:x:sync
/s

#####查网卡ip
[root@localhost awk]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
 .............
[root@localhost awk]# ip a  |awk -F "[ /]+" 'NR==3 {print $1}'

[root@localhost awk]# ip a  |awk -F "[ /]+" 'NR==3 {print $2}'
inet
[root@localhost awk]# ip a  |awk -F "[ /]+" 'NR==3 {print $3}'
127.0.0.1
[root@localhost awk]# 
 

awk模式匹配

  • awk -F "[ /]+" 'NR==3{print $3}'
  • 简单来说模式匹配就是,谁可以作为awk的条件
awk -F "[ /]+" 'NR==3{print $3}'
命令 选项 '条件{动作}'
'找谁{干啥}'
'模式{动作}'
'pattern{action}'
  1. **比较符号 ** (参考取行):> < >= <= == !=

  2. 正则:

    正则 awk正则
    ^表示以.....开头的行 某一列的开头$3~/^oldboy/
    $表示以......结尾的行 某一列的结尾
    ^$表示空行 某一列是空的 (很少用)
    • // 支持扩展正则
    • awk可以精确到某一列,某一列中包含/不包含的内容.
    • ~包含
    • !~不包含
    ####查看passwd文件中第散列包含1024的
    [root@localhost awk]# awk -F: '$3~/1024/{print $1}' /etc/passwd
    mrrxu00002
    [root@localhost awk]# awk -F: '/1024/{print $3}' /etc/passwd
    1023
    1024
    [root@localhost awk]#
    [root@localhost awk]# awk -F: '/1024/{print $0}' /etc/passwd
    mrrxu00001:x:1023:1024::/home/mrrxu00001:/bin/bash
    mrrxu00002:x:1024:1025::/home/mrrxu00002:/bin/bash
    [root@localhost awk]# awk -F: '/1024/' /etc/passwd
    mrrxu00001:x:1023:1024::/home/mrrxu00001:/bin/bash
    mrrxu00002:x:1024:1025::/home/mrrxu00002:/bin/bash
    [root@localhost awk]# 
    ##############找出 第三列以2开头的行,并显示第1列,第3列和最后一列
    [root@localhost awk]# awk -F: '$3~/^2/{print $1,$3,$NF}' /etc/passwd|column -t
    daemon   2   /sbin/nologin
    rpcuser  29  /sbin/nologin
    mysql    27  /bin/false
    [root@localhost awk]# 
    
    
    
  3. 范围表达式

    • /哪里开始/,/哪里结束/ 常用
    • NR1,NR5 从第1行开始到第5行结束 类似于sed -n '1,5p'
    ###显示指定时间范围内容的ip地址
    
    
  4. 特殊条件:BEGIN{}和END{}

模式 含义
BEGIN{} 里面的内容会在awk读取文件之前执行。 1.进行简单统计,计算,不涉及读取文件(常见)
2.用来处理文件之前,添加个表头(了解)
3.用来定义awk变量(很少用,因为可以用-v)
END{} 里面的内容会在awk读取文件之后执行。 1.awk进行统计时,一般过程:先进行计算,最后END里面输出(常见)
2.awk使用数组,用来输出数组结果(常见)
  • END{}统计计算
  • 统计方法:
统计方法 简写形式
i=i++ i++ 计数,统计次数
sum=sum+??? sum+=??? 求和累加
注意:i,sum都是变量
###统计/etc/service
[root@localhost awk]# grep '^$' /etc/services |wc -l
17
[root@localhost awk]# 
[root@localhost awk]# awk  '/^$/{i++}END{print i}'  /etc/services 
17
[root@localhost awk]# 
####从1++100求和
[root@localhost awk]# seq 1 100 |awk '{sum=sum+$1}END{print sum}'
5050
[root@localhost awk]# 如果要执行过程可打印sum值
[root@localhost awk]# seq 10 |awk '{sum=sum+$1;print sum}END{print sum}'
1
3
6
10
15
21
28
36
45
55
55
[root@localhost awk]# 

awk数组

  • 统计日志:类似于
  • 统计次数:统计每个ip出现次数,统计每种状态码出现次数,统计系统中每个用户被攻击的次数,或者统计攻击者ip出现次数,
  • 累加求和:统计每个ip消耗的流量
shell数组 awk数组 awk循环for
形式 array[0]=hello array[1]=world array[0]=hello array[1]=world
使用 echo ${array[0]} $ print array[0] array[1]
awk数组专用循环记得加() 只试用数字这类;注意不要和数组的使用方式混了
批量输出数组内容 for i in ${array[*]}
do
echo $i
done
for(i in array)
print i,array[i]或者
for(i=1;i<=NF;i++)
print i

注意

[root@localhost awk]# awk 'BEGIN{a[0]=hello; a[1]=world;print a[0] a[1]}'

[root@localhost awk]# 
[root@localhost awk]# awk 'BEGIN{a[0]="hello";a[1]="world";print a[0]"LEEO"a[1]}'
helloLEEOworld
[root@localhost awk]# 
###################################
[root@localhost awk]# awk 'BEGIN{array[0]="hello";array[1]="world";for (i in array) print i,array[i]}'
0 hello
1 world
[root@localhost awk]# 

注意:awk字母 会被识别为变量,如果只是想使用字符串需要使用双引号引起来

数组经典案例

######数组经典案例
#####################
####awk的分类汇总
#处理以下文件内容,将域名取出来并根据域名进行计数排序处理处理:
###计量
####array[]+++,你要统计什么   []里面就是什么(某一列)
##sort -rnk2    r是逆序n是数字k2是根据第二列
[root@localhost awk]# awk -F'/' '{array[$3]++ }END{for (j in array) print j ,array[j]}' awkeg.log |sort -rnk2
www.etiantian.org 3
post.etiantian.org 2
mp3.etiantian.org 1
[root@localhost awk]# 
###求和
[root@localhost awk]# awk -F' |/' '{a[$3]+=$5}END{for (j in a) print j,a[j]}' awkeg.log 
mp3.etiantian.org 21
www.etiantian.org 63
post.etiantian.org 2
[root@localhost awk]# cat awkeg.log 
http://www.etiantian.org/index 21
http://www.etiantian.org/index 21
http://post.etiantian.org/index 1
http://mp3.etiantian.org/index 21
http://www.etiantian.org/index 21
http://post.etiantian.org/index 1
[root@localhost awk]# 
[root@localhost awk]# cat -n awktest.log 
     1	总用量 120
     2	-rw-r--r--. 1 root root   253 9月   5 15:48 !
     3	-rw-r--r--. 1 root root     0 11月 28 10:07 10
     4	-rw-r--r--. 1 root root     0 11月 28 10:07 11
     5	-rw-r--r--. 1 root root     0 11月 28 10:07 12
     6	drwxr-xr-x. 2 root root    24 11月 21 11:28 array
     7	drwxr-xr-x. 2 root root    70 12月 14 10:49 awk
     8	-rw-r--r--. 1 root root    27 9月  19 14:41 calcualation2.sh
     9	-rw-r--r--. 1 root root  1886 9月  19 14:19 calcualation.sh
    10	-rw-r--r--. 1 root root   970 9月  19 17:32 checked.sh
    11	drwxr-xr-x. 2 root root    59 10月 30 14:46 color
.......
###,1至3行第一列已-开头的行,记录数和总文件的大小之和
[root@localhost awk]# awk 'NR>=1&&NR<=3&&$1~/^-/{count[i++]=$5;sum=sum+$5}END{ for (j in count) s=s+count[j];print i,s ,sum}' awktest.log 
2 253 253
[root@localhost awk]# 



注意:sort -rnk2 r是逆序n是数字k2是根据第二列

awk的循环和判断

常用的

  1. for循环

    #一般格式
    for  n in 1 3  5
    do
    	echo $n
    done
    
    shell编程c语言for循环 awk for循环
    for((i=1;i<=10;i++))
    do
    echo $i
    done
    for(i=1;i<=10;i++)
    print i
    awk的for循环一般用来循环某个字段
    一般用NF替换10,循环所有列
    [root@localhost awk]# awk 'BEGIN{ for (i=1;i<=10;i++) sum+=i; print sum}'
    55
    [root@localhost awk]# awk 'BEGIN{ for (i=1;i<=10;i++) {sum+=i; print sum}}'
    1
    3
    6
    10
    15
    21
    28
    36
    45
    55
    [root@localhost awk]# 如果要语句也跟着循环需要加上{}
    ################这样也是显示详细过程
    
    
  2. if判断

    shell中的if判断 awk 中的if
    if[ "oldbo" -ge 18 ]; then
    echo "good man go to dbj"
    fi
    if(条件)
    print "hello"
    if[ "oldbo" -ge 18 ]; then
    echo "good man go to dbj"
    else
    echo "good night"
    fi
    ####案例磁盘告警
    [root@localhost awk]# df -h
    文件系统                 容量  已用  可用 已用% 挂载点
    devtmpfs                 479M     0  479M    0% /dev
    tmpfs                    496M     0  496M    0% /dev/shm
    tmpfs                    496M  7.7M  488M    2% /run
    tmpfs                    496M     0  496M    0% /sys/fs/cgroup
    /dev/mapper/centos-root   17G  7.9G  9.2G   47% /
    /dev/sda1               1014M  197M  818M   20% /boot
    /dev/sdb1                999M  2.6M  928M    1% /home/newdisk
    tmpfs                    100M   28K  100M    1% /run/user/0
    /dev/sr0                  74M   74M     0  100% /run/media/root/VBox_GAs_6.0.20
    [root@localhost awk]# 
    
    root@localhost awk]# df -h|awk -F'[ %]+' '{if($5>50) print "disk is not enough"}' 
    disk is not enough
    disk is not enough
    [root@localhost awk]# df -h|awk -F'[ %]+' '{if($5>50) print "disk is not enough",$0}' 
    disk is not enough 文件系统                 容量  已用  可用 已用% 挂载点
    disk is not enough /dev/sr0                  74M   74M     0  100% /run/media/root/VBox_GAs_6.0.20
    [root@localhost awk]# df -h|awk -F'[ %]+' 'NR>1{if($5>50) print "disk is not enough",$0}' 
    disk is not enough /dev/sr0    
    ###:awk使用多个条件的时候,   第一个条件可以放在 '条件{动作}'  第二个条件一般使用if
    

    注意:awk使用多个条件的时候, 第一个条件可以放在 '条件{动作}' 第二个条件一般使用if

经典案例:统计这段语句中,单词中字符数大于5的

####awk有length函数统计字符长度。
[root@localhost awk]# echo  I am oldboy teacheer  welcome to oldboy training class|awk  '{for (i=1;i<=NF;i++) if( length($i)>5) print $i}'
oldboy
teacheer
welcome
oldboy
training
[root@localhost awk]#

###测试BEGIN和END块的区别
[root@localhost ~]# echo  I am oldboy teacheer  welcome to oldboy training class|awk  'BEGIN{for (i=1;i<=8;i++) if( length($i)>5) print $i}'
[root@localhost ~]####上面使用BEGIN块打印空,就能看错区别了,还没读入之前执行。
[root@localhost ~]# echo  I am oldboy teacheer  welcome to oldboy training class|awk  'END{for (i=1;i<=8;i++) if( length($i)>5) print $i}'
oldboy
teacheer
welcome
oldboy
training
[root@localhost ~]# echo  I am oldboy teacheer  welcome to oldboy training class|awk  '{for (i=1;i<=8;i++) if( length($i)>5) print $i}'
oldboy
teacheer
welcome
oldboy
training
[root@localhost ~]# 

awk总结

  • gawk gnu awk
  • awk选项 -F -v
  • awk执行流程
  • awk去行取列
  • awk模式:正则,范围,特殊模式,比较
  • awk数组:统计分析日志
  • awk for if
  • man awk /info awk
  • 目标
    • 计算次数
    • 求和