shell实战正则三贱客——awk
特点及应用场景
awk | ||
---|---|---|
一门语言类似于c语言 | ||
过滤,统计,计算 | ||
过滤,统计,日志 | ||
执行过程
awk -F, 'BEGIN{print "name"}{print $2}END{print "end of file"}' oldboy.txt
执行过程说明
- awk读取文件之前
-
- 命令复制或命令行参数 (-F 或- v)
- BEGIN{} (执行里面的内容,里面的内容会在awk读取文件之前执行)
- awk读取文件时(找谁干啥)
- 读取文件的一行
- 是否满足条件 :
- 1)满足,则执行对应的动作 {print $2} 然后向下继续;
- 2)不满足则向下继续
- 是否最后一行
- 1)不满足则继续读取文件下一行
- 2)满足 则向下继续
- awk读取文件之后
- END{} (里面的内容会在awk读取文件之后执行显示结果)
- 结束
行与列
名词 | 说明 | |
---|---|---|
行 | 记录 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}' |
-
**比较符号 ** (参考取行):> < >= <= == !=
-
正则:
正则 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]#
-
范围表达式:
- /哪里开始/,/哪里结束/ 常用
- NR1,NR5 从第1行开始到第5行结束 类似于sed -n '1,5p'
###显示指定时间范围内容的ip地址
-
特殊条件: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的循环和判断
常用的
-
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
donefor(i=1;i<=10;i++)
print iawk的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]# 如果要语句也跟着循环需要加上{} ################这样也是显示详细过程
-
if判断
shell中的if判断 awk 中的if if[ "oldbo" -ge 18 ]; then
echo "good man go to dbj"
fiif(条件)
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
- 目标
-
- 计算次数
- 求和