其他
正则表达式(7)-三剑客之awk(2)
每周二、四、六定期更新!
awk变量
awk的变量和shell一样,也分为内部变量和自定义变量。
awk的“-v”选项用来定义变量或为变量赋值。
常见的内置变量:
FS:(field separator)定义输入分隔符,默认为空格。功能相当于“-F”选项。
[root@studyclub jason]# awk -v FS=: '{print $1,$7}' /etc/passwd # 指定分隔符为“:”
[root@studyclub jason]# awk -v FS=: '{print $1,FS,$7}' /etc/passwd # 指定分隔符为“:”,并且在输出的时候用到了这个分隔符
[root@studyclub jason]# awk -v FS=: -v OFS=@@@ '{print $1,$7}' /etc/passwd # 指定输出分隔符为@@@
RS:(record separator)指定每个记录之间的分隔符,这个分隔符用来区分一条记录到哪地方结束。默认是换行符,所以我们上面介绍的时候说“文件的每一行称为一个记录”。如果记录的分隔符不是默认的换行符,那么一行里可能会有多个记录。
# 我们先准备一下需要使用的文件
[root@studyclub jason]# cat awk.txt
1,2,3/aa,bb,cc/jason,
james/eric,simon/
88jie,wukong/wujing
# 以逗号为分隔符,把每个记录分割出来并打印每条记录的第一个和第二个字段。
[root@studyclub jason]# awk -F, -v RS=/ '{print $1,$2}' awk.txt
1 2
aa bb
jason
james
eric simon
# 注意:这里分完记录“/”的后面还有一个回车换行符,所以这里的回车换行符和88jie一块才是$1
88jie wukong
wujing
# 注意:wujing后面还有个回车换行符,所以这里有个空行
# 我们指定一下分隔符,看的更明白。指定输出分隔符为分号“;”
[root@studyclub jason]# awk -F, -v RS=/ -v OFS=";" '{print $1,$2}' awk.txt
1;2 # 同一个记录内的才有分号分隔符,不同记录之间是没有分号分隔符的。
aa;bb
jason;
james
eric;simon
88jie;wukong
wujing
;
[root@studyclub jason]# awk -F, -v RS=/ -v OFS=";" '{print NF}' awk.txt
3
3
2
2
2
1
[root@studyclub jason]# awk -F, -v RS=/ -v OFS=";" '{print $NF}' awk.txt
# 查看有哪些客户端连接到了本机(可以根据这个来判断哪些机器连接太多,看看是不是恶意攻击的设备)
[root@studyclub jason]# ss -nt | grep ^ESTAB | awk -F "[[:space:]]+|:" '{print $(NF-2)}'
10.0.0.1
注意看上面两个命令,区别就是NF和$NF,NF是有多少个字段,$NF就是代表最后一个字段。如果取倒数第二个字段呢?那就用$(NF-1)呗。自己练习一下吧!
通过上面的例子我们也可以发现-F和指定的分隔符之间可以有空格,也可以没有空格
# 先找到哪个客户端连接的最多
[root@studyclub jason]# ss -nt | grep ^ESTAB | awk -F "[[:space:]]+|:" '{print $(NF-2)}' | sort | uniq -c | sort -r
4 10.0.0.138
1 10.0.0.1
# 我们通过写脚本完成连接数超过3个的就禁止连接
[root@studyclub script]# cat deny_flood.sh
#!/bin/bash
# 篇幅有限,这里就不体现说明信息了,只上干货
while true;
do
ss -nt| grep ^ESTAB | awk -F "[[:space:]]+|:" '{print $(NF-2)}' | sort | uniq -c | sort -r | while read connect_count ip;do
if [ $connect_count -gt 3 ];then
iptables -A INPUT -s $ip -j REJECT
fi
done
sleep 20
done
# 我们来看执行后的效果,10.0.0.138被禁用了吧!
[root@studyclub script]# iptables -vnL
Chain INPUT (policy ACCEPT 14 packets, 852 bytes)
pkts bytes target prot opt in out source destination
2 104 REJECT all -- * * 10.0.0.138 0.0.0.0/0 reject-with icmp-port-unreachable
# 默认换行符作为记录的分隔符,查看记录编号。使用默认换行符作为记录的分隔符的情况下,NR也就是行号。
[root@studyclub script]# awk '{print NR}' /etc/passwd
1
...... # 篇幅有限,省略中间结果
33
# 使用指定的冒号作为记录的分隔符,查看记录编号
[root@studyclub script]# awk -v RS=: '{print NR}' /etc/passwd
# 只统计最后一个记录的编号,通过这个可以确认总记录数。
[root@studyclub script]# awk -v RS=: 'END{print NR}' /etc/passwd
199
# 请注意和上面的NR的实例的结果做对比。
[root@studyclub script]# awk '{print FNR}' /etc/passwd /etc/hosts
1
...... # 篇幅有限,省略中间结果
33
1
2
# 打印当前处理文本的文件名
[root@studyclub script]# awk '{print FILENAME}' /etc/passwd
/etc/passwd
......
/etc/passwd
[root@studyclub script]# awk '{print ARGC}' /etc/passwd /etc/issue /etc/hosts
4
......
4
# 一开始统计一次就好了,不用每一个记录都打印参数个数:
[root@studyclub script]# awk 'BEGIN{print ARGC}' /etc/passwd /etc/issue /etc/hosts
4
[root@studyclub script]# awk 'BEGIN{print ARGV[0]}' /etc/passwd /etc/issue /etc/hosts
awk
[root@studyclub script]# awk 'BEGIN{print ARGV[1]}' /etc/passwd /etc/issue /etc/hosts
/etc/passwd
[root@studyclub script]# awk 'BEGIN{print ARGV[2]}' /etc/passwd /etc/issue /etc/hosts
/etc/issue
自定义变量
通过awk的-v参数可以实现定义自己需要的变量:
在命令执行部分直接定义
# 方法1:通过-v参数定义
[root@studyclub script]# awk -v home="studyclub" 'BEGIN{print home}' # 加两个BEGIN说明和文件没有关系了,所以后面不需要再加文件名
studyclub
# 方法2:在命令执行部分直接定义
[root@studyclub script]# awk 'BEGIN{home="studyclub";print home}'
studyclub
# 练习:把方法2,转换成使用-f选项实现:
[root@studyclub script]# cat awkfile.awk # 把''内的内容放入一个文件,注意:不要把引号本身''写入到文件中。
BEGIN{home="studyclub";print home}
[root@studyclub script]# awk -f awkfile.awk # 通过-f选项使用上面创建的文件
studyclub
《Linux基础及进阶》:
061 - 正则表达式(2)-基本正则表达式2 062 - 正则表达式(3)-扩展正则表达式 063 - 正则表达式(4)-三剑客之grep 064 - 正则表达式(5)-三剑客之sed 065 - 正则表达式(6)-三剑客之awk(1)看完本文有收获?请分享给更多人
推荐关注「Cloud研习社」,带你从零开始掌握云计算技术!
微信号|bjdream-1
Cloud研习社 ·