文本三剑客
grep 命令主要对文本的行基于模式进行过滤
sed 文本编辑工具
awk 文本报告生成器
1. grep
作用:文本搜索工具,根据用户指定的模式对目标文件逐行进行批评检查
模式:由正则表达式及文本字符所编写的过滤条件
格式:
grep [optiona] pattern [file]
选项
- -color=auto 对匹配到的文本着色显示
- -m # 匹配#次后停止
- -v 显示不被pattern匹配的行,取反
- -i 忽略大小写
- -n 显示匹配的行号
- -c 统计匹配的行数
- -o 仅显示匹配的字符串
- -q 静默模式,不输出任何信息
- -A # 后#行
- -B # 前#行
- -C # 前后各#行
- -e 或
- -w 匹配整个单词
- -E 扩展正则表达式
- -F 不支持使用正则表达式
- -f file 根据模式文件处理
- -r 递归目录,但不处理软链接
- -R 递归目录,处理软链接
范例:取2个文件相同的行
[root@centos8 ~]#cat f1.txt
a
b
1
c
[root@centos8 ~]#cat f2.txt
b
e
f
c
1
2
[root@centos8 ~]#grep -f f1.txt f2.txt
b
c
1
范例:分区利用率最大的值
[root@centos8 ~]#df |grep '^/dev/sd'|tr -s ' ' % |cut -d% -f5|sort -nr|head -n1
14
范例:那个ip和当前主机连接数最多
[root@centos8 ~]#ss -nt |grep '^ESTAB'|tr -s ' ' : |cut -d: -f6|sort |uniq -c|sort -nr|head -n1
4 10.0.0.1
范例:连接状态统计
[root@centos8 ~]#ss -nta|grep -vi '^state'|cut -d' ' -f1|sort|uniq -c |sort -nr
4 LISTEN
4 ESTAB
[root@centos8 ~]#ss -nta |tail -n +2|cut -d' ' -f1 |sort |uniq -c
4 ESTAB
4 LISTEN
范例:取IP
[root@centos8 ~]#ifconfig |grep -o '\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}'|head -n1
10.0.0.101
[root@centos8 ~]#ifconfig |grep 'netmask'|grep -o '\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}'|head -n1
10.0.0.101
范例:取用户名和shell同名的
[root@centos8 ~]#grep -E '^(.*)\>.*\<\b\1$' /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
范例:计算所有人年龄总和
xiaoming=20
xiaowang=18
xiaoqiang=22
[root@centos8 ~]#cut -d= -f2 f1.txt | paste -sd+ |bc
60
[root@centos8 ~]#grep -Eo '[0-9]+' f1.txt |tr '\n' '+'|grep -Eo '.*[0-9]'|bc
60
[root@centos8 ~]#grep -Eo '[0-9]+' f1.txt |paste -sd+|bc
60
2. sed
sed 和vi不同,sed是行编辑器
sed是从文件或管道中读取一行,处理一行,输出一行,再读取,至到最后一行
每当处理一行是,把当前处理的行存储在临时缓冲区中,称为模式空间
2.1 sed的基本用法
格式
sed [option] .. 'script;script' inputfile
选项
- -n 取消自动打印
- -e 多点编辑
- -f FILE 从指定文件读取编辑脚本
- -r,-E 使用扩展的正则表达式
- -i.bak 备份并在源文件编辑
script 格式
'地址命令'
地址格式:
-
不给地址,对全文进行处理
-
单地址
#:指定的行,$:最后一行
/pattren/:被此处模式匹配的每一行 -
地址范围:
#,# 从哪行到哪行
#,+# 从哪行到后#行
/pat1/,/pat2/ 从匹配pat1的行到匹配pat2的行
#,/pat/ 从#行到匹配的pat的行 -
步进:~
1~2 奇数行
2~2 偶数行
命令: -
p 打印当前模式空间的内容,追加到默认输出之后
-
Ip 忽略大小写
-
d 删除模式空间的行
-
a 在真的行后面追加文本,支持使用\n实现多行zhuijia
-
i 在行前面插入文本
-
c 替换行或多行文本
-
w file 保存模式匹配的行到指定文件
-
r file 读取指定的文件的文本只模式空间匹配到的行
-
= 为模式空间中的行打印行号
-
! 模式空间中匹配的行取反
-
s/pattern/string/修饰符 查找替换
替换修饰符:
g 行内全局替换
p 显示替换成功的行
w /PATH/FILE 将替换成功的行保存至文件中
I,i 忽略大小写
范例:获取分区利用率
[root@centos8 ~]#df |sed -rn '/^\/dev\/sda/s/.* ([0-9]+)%.*/\1/p'
2
1
14
范例:取IP
[root@centos8 ~]#ifconfig eth0 |sed -nr "2s/[^0-9]+([0-9.]+).*/\1/p"
10.0.0.8
[root@centos6 ~]#ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*/\1/p'
10.0.0.6
[root@centos8 ~]#ifconfig eth0 | sed -rn '2s/^[^0-9]+([0-9.]+) .*$/\1/p'
10.0.0.8
[root@centos8 ~]#ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/ netmask.*//p'
10.0.0.8
[root@centos8 ~]#ifconfig eth0 | sed -n '2s/^.*inet //;s/ netmask.*//p'
10.0.0.8
[root@centos8 ~]#ifconfig eth0 | sed -rn '2s/(.*inet )([0-9].*)( netmask.*)/\2/p'
10.0.0.8
范例:取基名和目录名
echo "/etc/sysconfig/network-scripts/" |sed -r 's#(^/.*/)([^/]+/?)#\2#' 取基名
echo "/etc/sysconfig/network-scripts/" |sed -r 's#(^/.*/)([^/]+/?)#\1#' 取目录
#取目录名
[root@centos8 ~]#echo /etc/sysconfig/ | sed -rn 's#(.*)/([^/]+)/?#\1#p'
/etc
#取基名
[root@centos8 ~]#echo /etc/sysconfig/ | sed -rn 's#(.*)/([^/]+)/?#\2#p'
sysconfig
范例:取文件的前后缀
[root@centos8 data]#echo a.b.c.gz |sed -En 's/(.*)\.([^.]+)$/\1/p'
a.b.c
[root@centos8 data]#echo a.b.c.gz |sed -En 's/(.*)\.([^.]+)$/\2/p'
gz
[root@centos8 data]#echo a.b.c.gz |grep -Eo '.*\.'
a.b.c
[root@centos8 data]#echo a.b.c.gz |grep -Eo '[^.]+$'
gz
范例:将非#开头的行加#
[root@centos8 ~]#sed -rn "s/^[^#]/#&/p" /etc/fstab
#UUID=1b950ef9-7142-46bd-975c-c4ac1e0d47e8 / xfs defaults 0 0
#UUID=667a4c81-8b4b-4a39-a111-b11cb6d09309 /boot ext4 defaults 1 2
#UUID=38d14714-c018-41d5-922c-49e415decbca /data xfs defaults 0 0
#UUID=a0efb2bb-8227-4317-a79d-0a70d515046c swap swap defaults 0 0
[root@centos8 ~]#sed -rn 's/^[^#](.*)/#\1/p' /etc/fstab
#UID=1b950ef9-7142-46bd-975c-c4ac1e0d47e8 / xfs defaults 0 0
#UID=667a4c81-8b4b-4a39-a111-b11cb6d09309 /boot ext4 defaults 1 2
#UID=38d14714-c018-41d5-922c-49e415decbca /data xfs defaults 0 0
#UID=a0efb2bb-8227-4317-a79d-0a70d515046c swap swap defaults 0 0
[root@centos8 ~]#sed -rn '/^#/!s@^@#@p' /etc/fstab
#
#UUID=1b950ef9-7142-46bd-975c-c4ac1e0d47e8 / xfs defaults 0 0
#UUID=667a4c81-8b4b-4a39-a111-b11cb6d09309 /boot ext4 defaults 1 2
#UUID=38d14714-c018-41d5-922c-49e415decbca /data xfs defaults 0 0
#UUID=a0efb2bb-8227-4317-a79d-0a70d515046c swap swap defaults 0 0
范例:将#开头的行删除#
[root@centos8 ~]#sed -ri.bak '/^#/s/^#//' /etc/fstab
范例:取分区利用率
[root@centos8 ~]#df | sed -nr '/^\/dev\/sd/s# .* ([0-9]+)%.*# \1#p'
/dev/sda2 3
/dev/sda5 1
/dev/sda1 14
范例:修改内核参数
[root@centos8 ~]#sed -nr '/^GRUB_CMDLINE_LINUX/s/"$/ net.ifnames=0"/p' /etc/default/grub
GRUB_CMDLINE_LINUX="crashkernel=auto resume=UUID=8363289d-138e-4e4a-abaf-6e028babc924 rhgb quiet net.ifnames=0"
[root@centos8 ~]#sed -rn '/^GRUB_CMDLINE_LINUX=/s@(.*)"$@\1 net.ifnames=0"@p' /etc/default/grub
GRUB_CMDLINE_LINUX="crashkernel=auto resume=UUID=a0efb2bb-8227-4317-a79d-0a70d515046c rhgb quiet net.ifnames=0"
[root@centos8 ~]#sed -rn '/^GRUB_CMDLINE_LINUX=/s@"$@ net.ifnames=0"@p' /etc/default/grub
GRUB_CMDLINE_LINUX="crashkernel=auto resume=UUID=a0efb2bb-8227-4317-a79d-0a70d515046c rhgb quiet net.ifnames=0 net.ifnames=0"
范例:修改网卡名
#centos7,8
[root@centos8 ~]#sed -i '/GRUB_CMDLINE_LINUX=/s#quiet#& net.ifnames=0#' /etc/default/grub
[root@centos8 ~]#sed -ri '/^GRUB_CMDLINE_LINUX=/s@"$@ net.ifnames=0"@' /etc/default/grub
[root@centos8 ~]#grub2-mkconfig -o /boot/grub2/grub.cfg
#ubuntu
[root@ubuntu ~]#grub-mkconfig -o /boot/grub/grub.cfg
范例:查看配置文件
sed -r '/^(#|$)/d' /etc/httpd/conf/httpd.conf
sed -r '/^#|^$/d' /etc/httpd/conf/httpd.conf
范例:引用变量
[root@centos8 ~]#echo|sed "s/^/$RANDOM.rmvb/"
5242.rmvb
[root@centos8 ~]#echo|sed 's/^/$RANDOM.rmvb/'
$RANDOM.rmvb
[root@centos8 ~]#echo|sed 's/^/'''$RANDOM'''.rmvb/'
范例:修改配置文件
[root@centos6 ~]#sed -e '/^#<VirtualHost/,/^#<\/VirtualHost>/s@#@@' -e '/^#NameVirtualHost/s@#@@' /etc/httpd/conf/httpd.conf
2.2 sed高级用法
sed中除了模式空间,还另外支持保持空间(Hold Space),利用此空间,可以将模式空间中的数据,临时保存至保持空间,从而后续接着处理,实现更为强大的功能
常见的高级命令
P 打印模式空间开端至\n内容,并追加到默认输出之前
h 把模式空间中的内容覆盖至保持空间
H 把模式空间中的内容追加至保持空间中
g 从保持空间取出数据覆盖至模式空间
G 从保持空间取出内容追加至模式空间
x 把模式空间中的内容和保持空间中的内容进行互换
n 读取匹配到的行的下一行覆盖至模式空间
N 读取匹配到的行的下一行追加至模式空间
d 删除模式空间中的行
D 如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入行,而使用合成的模式空间重新启动循环。如果模式空间不包含换行符,则会像发出d命令那样启动正常的新循环
范例:
sed -n 'n;p' FILE 显示偶数行
seq 10 | sed 'N;s/\n//' 将2行合并成一行显示
sed '1!G;h;$!d' FILE 倒序
sed 'N;D' FILE 显示最后一行
seq 10 |sed '3h;9G;9!d' 只显示3和9行,显示为9行和3行
sed '$!N;$!D' FILE 显示最后2行
sed '$!d' FILE 显示最后一行
sed 'G' FILE 在每行加一行空行
sed 'g' FILE 全部显示空行
sed '/^$/d;G' FILE 删除空行,并在每行加一行空行
sed 'n;d' FILE 显示奇数行
sed -n '1!G;h;$p' FILE 倒序
3. awk
3.1 awk基本用法
awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWKa
wk有多种版本
- AWK:原先来源于 AT & T 实验室的的AWK
- NAWK:New awk,AT & T 实验室的AWK的升级版
- GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容
gawk:模式扫描和处理语言,可以实现下面功能 - 文本处理
- 输出格式化的文本报告
- 执行算数运算
- 执行字符串操作
awk [options] 'program' var=value file..
awk [options] -f programfile var=value file…
说明:
program通常是被放在单引号中,并可以由三种部分组成
- BEGIN语句块
- 模式匹配的通用语句块
- END语句块
常见选项
- -F“分割符”指明输入时用到的字段分隔符,默认的分隔符是若干个连续的空白符
- -v var=value 变量赋值
3.1.1 Program格式
pattern{action statements;..}
pattren:决定动作语句何时触发及触发事件,比如:BEGIN,END,正则表达式等
action statements:对数据进行处理,放在{}内指明,常见:print,printf
3.1.2 awk工作过程
第一步:执行BEGIN{action;…}语句块的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{action;…}语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕
第三步:当读至输入流末尾时,执行END{action;…}语句块
ENGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流读取万搜易行之后即被执行,比如打印所有行的分析结构这类信息汇总都是在END语句块中完成,它也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print},即打印每一个读取到的行,awk读取的每一行都会执行该语句块
3.1.3 分隔符、域和记录
- 由分隔符分割的字段(列column,域field)标记$1,$2…$n称为域标识,$0为所有域,注意:和shell中的变量$符含义不同
- 文件的每一行称为记录record
- 如果省略action,则默认执行print $0
3.1.4 常见的action分类
- output statements:print,printf
- Expressions:算术,比较表达式等
- Compound statements:组合语句
- Control statements:if,while等
- input statements
3.1.5 awk控制语句
- {statements;…}组合语句
- if(condition){statements;…}
- if(condition){statements;…} else{statements;…}
- while(condition){statements;…}
- do{statements;…} while(condition)
- for(expr1;expr2;expr3){statements;…}
- break
- continue
- exit
3.2 动作print
格式:
print item1, item2, ...
说明
- 逗号分隔符
- 输出item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式
- 如省略item,相当于print $0
- 固定字符需要用“”引起来,而变量和数字不需要
范例:
[root@centos8 ~]#awk '{print "hello,awk"}'
[root@centos8 ~]#seq 10 | awk '{print "hello,awk"}
[root@centos8 ~]#seq 3 | awk '{print 2*3}'
6
6
6
[root@centos8 ~]#awk -F: '{print "wang"}' /etc/passwd
[root@centos8 ~]#awk -F: '{print}' /etc/passwd
[root@centos8 ~]#awk -F: '{print $0}' /etc/passwd
[root@centos8 ~]#awk -F: '{print $1,$3}' /etc/passwd
[root@centos8 ~]#awk -F: '{print $1"\t"$3}' /etc/passwd
面提:取出网络访问量最大的前3IP
[root@VM_0_10_centos logs]# awk '{print $1}' nginx.access.log-20200428|sort | uniq -c |sort -nr|head -3
5498 122.51.38.20
2161 117.157.173.214
953 211.159.177.120
[root@centos8 ~]#awk '{print $1}' access_log |sort |uniq -c|sort -nr|head
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
2613 172.20.112.14
2267 172.20.0.227
2262 172.20.116.179
2259 172.20.65.65
1565 172.20.0.76
1482 172.20.0.200
1110 172.20.28.145
面题:取出分区利用率
[root@centos8 ~]#df | awk '{print $1,$5}'
Filesystem Use%
devtmpfs 0%
tmpfs 0%
tmpfs 2%
tmpfs 0%
/dev/sda2 3%
/dev/sda3 1%
/dev/sda1 15%
tmpfs 0%
[root@centos8 ~]#df | awk -F"[[:space:]]+|%" '{print $5}'
Use
001051
92
1
[root@centos8 ~]#df | awk -F'[[:space:]]+|%' '{print $1,$5}'
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 2
tmpfs 0
/dev/sda2 3
/dev/sda3 1
/dev/sda1 15
tmpfs 0
[root@centos8 ~]#df | grep "^/dev/sd" | awk -F"[[:space:]]+|%" '{print $5}'
51
92
[root@centos8 ~]#df | grep '^/dev/sd'| awk -F'[[:space:]]+|%' '{print $1,$5}'
/dev/sda2 3
/dev/sda3 1
/dev/sda1 15
[root@centos8 ~]#df | awk -F"[[:space:]]+|%" '/^\/dev\/sd/{print $5}'
51
92
[root@centos8 ~]#df | awk -F'[[:space:]]+|%' '/^\/dev\/sd/{print $1,$5}'
/dev/sda2 3
/dev/sda3 1
/dev/sda1 15
[root@centos8 ~]#df|awk -F' +|%' '/^\/dev\/sd/{print $1,$5}'
/dev/sda2 3
/dev/sda3 2
/dev/sda1 100
范例:取nginx的访问日志中的IP和时间
[root@VM_0_10_centos ~]# head -n 3 /apps/nginx/logs/nginx.access.log
58.87.87.99 - - [09/Jun/2020:03:42:43 +0800] "POST /wp-cron.php?doing_wp_cron=1591645363.2316548824310302734375 HTTP/1.1" ""sendfileon
128.14.209.154 - - [09/Jun/2020:03:42:43 +0800] "GET / HTTP/1.1" ""sendfileon
64.90.40.100 - - [09/Jun/2020:03:43:11 +0800] "GET /wp-login.php HTTP/1.1" ""sendfileon
[root@VM_0_10_centos ~]# awk -F'[[ ]' '{print $1,$5}' /apps/nginx/logs/nginx.access.log|head -3
58.87.87.99 09/Jun/2020:03:42:43
128.14.209.154 09/Jun/2020:03:42:43
64.90.40.100 09/Jun/2020:03:43:11
面试:取ifconfig输出结果中的IP地址
[root@centos8 ~]#hostname -I | cat -A
10.0.0.8 $
[root@centos8 ~]#ifconfig eth0|sed -n '2p' |awk '{print $2}'|cat -A
10.0.0.8$
[root@centos8 ~]#ifconfig eth0 | awk '/netmask/{print $2}'
10.0.0.8
[root@centos6 ~]#ifconfig eth0 |awk -F " +|:" '/Mask/{print $4}'
10.0.0.6
[root@centos6 ~]#ip a show eth0 |awk -F' +|\/' '/\<inet\>/{print $3}' 2> /dev/null
10.0.0.6
[root@centos8 ~]#ifconfig eth0| sed -rn '2s/^[^0-9]+([0-9.]+) .*$/\1/p'
10.0.0.8
[root@centos6 ~]#ifconfig eth0| sed -rn '2s/^[^0-9]+([0-9.]+) .*$/\1/p'
10.0.0.6
面题:文件host_list.log如下格式,请提取”.magedu.com“前面的主机名部分并写入到该文件中
[root@centos8 ~]#cat host_list.log
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
[root@centos8 ~]#awk -F"[ .]" '{print $2}' host_list.log
www
blog
study
linux
python
[root@centos8 ~]#awk -F"[ .]" '{print $2}' host_list.log >> host_list.log
[root@centos8 ~]#cat host_list.log
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
www
blog
study
linux
python
3.3 awk变量
awk中的变量分为:内置和自定义变量
3.3.1 常见的内置变量
3.3.1.1 FS
- FS:输入字段分割符,默认为空白字符,功能相当于-F
范例:
awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
awk -v FS=":" '{print $1FS$3}' /etc/passwd
awk –F: '{print $1,$3,$7}' /etc/passwd
S=:;awk -v FS=$S '{print $1FS$3}' /etc/passwd
[root@centos8 ~]#awk -v FS=":" '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2
[root@centos8 ~]#S=:;awk -F$S '{print $1,$3}' /etc/passwd|head -n3
root 0
bin 1
daemon 2
#-F 和 FS变量功能一样,同时使用会冲突
[root@centos8 ~]#awk -v FS=":" -F";" '{print $1FS$3}' /etc/passwd |head -n3
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@centos8 ~]#awk -F";" -v FS=":" '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2
#-F 和 FS变量功能一样,同时使用会 -F 优先级高
[root@centos8 ~]#awk -v FS=":" -F";" '{print $1}' /etc/passwd |head -n3
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@centos8 ~]#awk -v FS=";" -F":" '{print $1}' /etc/passwd |head -n3
root
bin
daemon
3.3.1.2 OFS
- OFS:输出字段分割符,默认为空白字符
[root@centos8 ~]#awk -v FS=':' '{print $1,$3,$7}' /etc/passwd|head -n1
root 0 /bin/bash
[root@centos8 ~]#awk -v FS=':' -v OFS=':' '{print $1,$3,$7}'
/etc/passwd|head -n1
root:0:/bin/bash
3.3.1.3 RS
- RS:输入记录record分隔符,指定输入时的换行符
awk -v RS=' ' '{print }' /etc/passwd
3.3.1.4 ORS
- ORS:输出记录分隔符,输出时用指定符号代替换行符
awk -v RS=' ' -v ORS='###' '{print $0}' /etc/passwd
3.3.1.5 NF
- NF:字段数量
#引用变量时,变量前不需加$
[root@centos8 ~]#awk -F:'{print NF}' /etc/fstab
[root@centos8 ~]#awk -F:'{print $(NF-1)}' /etc/passwd
[root@centos8 ~]#ls /misc/cd/BaseOS/Packages/*.rpm |awk -F"." '{print $(NF-1)}'|sort |uniq -c
389 i686
208 noarch
1060 x86_64
面题:连接数最多的前3个IP
[root@centos8 ~]#awk -F" +|:" '{print $(NF-2)}' ss.log |sort |uniq -c|sort -nr|head -n3
12 223.88.255.148
11 119.250.197.118
10 183.202.63.36
[root@centos8 ~]#awk -F" +|:" '/^ESTAB/{print $(NF-2)}' ss.log |sort |uniq -c|sort -nr|head -n3
12 223.88.255.148
10 183.202.63.36
9 117.152.155.119
[root@centos8 ~]#ss -nt |grep "^ESTAB" | awk -F"[[:space:]]+|:" '{print $(NF-2)}'
10.0.0.1
10.0.0.7
10.0.0.1
[root@centos8 ~]#ss -nt |awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'
[root@centos8 ~]#ss -nt|awk -F: '{print $(NF-1)}' |awk '/^[0-9]/{print $NF}'| sort |uniq -c |head -n 3
[root@wang-liyun-pc ~]# awk -F' +|:' 'NR!=1{print $(NF-2)}' ss.log|sort |uniq -c
1 100.100.30.25
86 39.164.140.134
范例:每十分钟检查将连接数超过100个以上的IP放入黑名单拒绝访问
[root@centos8 ~]#cat deny_dos.sh
LINK=100
while true;do
ss -nt | awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'|sort |uniq - c|while read count ip;do
if [ $count -gt $LINK ];then
iptables -A INPUT -s $ip -j REJECT
fi
done
done
[root@centos8 ~]#chmod +x /root/deny_dos.sh
[root@centos8 ~]#crontab -e
[root@centos8 ~]#crontab -l
*/10 * * * * /root/deny_dos.sh
[root@centos8 ~]#cat deny_dos.sh
IPLIST=`awk -F" +|:" '/^ESTAB/{print $(NF-2)}' ss.log |sort |uniq -c|sort -nr|head -3|awk '{print $2}'`
for ip in $IPLIST;do
iptables -A INPUT -s $ip -j REJECT
done
3.3.1.6 NR
- NR:记录的编号
[root@centos8 ~]#awk '{print NR,$0}' /etc/issue /etc/centos-release
1 \S
2 Kernel \r on an \m
34 CentOS Linux release 8.1.1911 (Core)
[root@centos8 ~]#awk -F: '{print NR}' /etc/passwd
1
2
3
.......
[root@centos8 ~]#awk -F: 'END{print NR}' /etc/passwd
57
[root@centos8 ~]#awk -F: 'BEGIN{print NR}' /etc/passwd
0
3.3.1.7 FNR
- FNR:各文件分别计数,记录的编号
awk '{print FNR}' /etc/fstab /etc/inittab
[root@centos8 ~]#awk '{print NR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
34 CentOS Linux release 8.0.1905 (Core)
[root@centos8 script40]#awk '{print FNR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
31 CentOS Linux release 8.0.1905 (Core)
3.3.1.8 FILENAME
- FILENAME:当前文件名
[root@centos8 ~]#awk '{print FILENAME}' /etc/fstab
[root@centos8 ~]#awk '{print FNR,FILENAME,$0}' /etc/issue /etc/redhat-release
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue
1 /etc/redhat-release CentOS Linux release 8.0.1905 (Core)
3.3.1.9 ARGC
- ARGC:命令行参数的个数
[root@centos8 ~]#awk '{print ARGC}' /etc/issue /etc/redhat-release
3
3
3
3
[root@centos8 ~]#awk 'BEGIN{print ARGC}' /etc/issue /etc/redhat-release
3
3.3.1.10 ARGV
- ARGV:数组,保存的是命令行所给定的各参数,每一个参数:ARGV[0],…
[root@centos8 ~]#awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release
awk
[root@centos8 ~]#awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release
/etc/issue
[root@centos8 ~]#awk 'BEGIN{print ARGV[2]}' /etc/issue /etc/redhat-release
/etc/redhat-release
[root@centos8 ~]#awk 'BEGIN{print ARGV[3]}' /etc/issue /etc/redhat-release
3.3.2 自定义变量
自定义变量是区分字符大小写的,使用下面方式进行赋值
- -v var=value
- 在program中直接定义
[root@centos8 ~]#awk -v test1=test2="hello,gawk" 'BEGIN{print test1,test2}'
test2=hello,gawk
[root@centos8 ~]#awk -v test1=test2="hello1,gawk" 'BEGIN{test1=test2="hello2,gawk";print test1,test2}'
hello2,gawk hello2,gawk
awk -v test='hello gawk' '{print test}' /etc/fstab
awk -v test='hello gawk' 'BEGIN{print test}'
awk 'BEGIN{test="hello,gawk";print test}'
awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd
3.4 动作printf
printf可以实现格式化输出
printf “FORMAT”, item1, item2, ...
说明:
- 必须指定FORMAT
- 不会自动换行,需要显式给出换行符\n
- FORMAT中需要分别为后面的每个item指定格式符
格式符:与item一一对应
%c:显示字符的ASII码
%d,%i:显示十进制整数
%e,%E:显示科学计数法数值
%f:显示为浮点数
%g,%G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%:显示%自身
修饰符
#[.#] 第一个数字控制显示的宽度;第二个#显示小数点后精度。如:%3.1f
- 左对齐(默认右对齐)如:%-15s
+ 显示数值的正负号,如:%+d
范例:
awk -F: '{printf "%s",$1}' /etc/passwd
awk -F: '{printf "%s\n",$1}' /etc/passwd
awk -F: '{printf "%20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
awk -F: '{printf “Username: %sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %25sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %-25sUID:%d\n",$1,$3}' /etc/passwd
3.5 操作符
算术操作符
x+y,x-y,x*y,x/y,x^y,x%y
-x:转换为负数
+x:将字符串转换为数值
字符串操作符:没有符号的操作符,字符串连接
3.5.1 赋值操作符
=, +=, -=, *=, /=, %=, ^=,++, --
范例
[root@centos8 ~]#awk 'BEGIN{i=0;print i++,i}'
0 1
[root@centos8 ~]#awk 'BEGIN{i=0;print ++i,i}'
1 1
范例
[root@centos8 ~]#awk -v n=0 '!n++' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos8 ~]#awk -v n=0 '!n++{print n}' /etc/passwd
1
[root@centos8 ~]#awk -v n=1 '!n++{print n}' /etc/passwd
[root@centos8 ~]#awk -v n=0 '!++n{print n}' /etc/passwd
[root@centos8 ~]#awk -v n=0 '!++n' /etc/passwd
[root@centos8 ~]#awk -v n=-1 '!++n' /etc/passwd
root:x:0:0:root:/root:/bin/bash
3.5.2 比较操作符
==, !=, >, >=, <, <=
范例
[root@centos8 ~]#awk 'NR==2' /etc/issue
Kernel \r on an \m
[root@centos8 ~]#awk -F: '$3>=1000' /etc/passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
wang:x:1000:1000:wang:/home/wang:/bin/bash
mage:x:1001:1001::/home/mage:/bin/bash
范例:取奇偶行
[root@centos8 ~]#seq 10 | awk 'NR%2==0'
2
4
6
8
10
[root@centos8 ~]#seq 10 | awk 'NR%2==1'
1
3
5
7
9
[root@centos8 ~]#seq 10 | awk 'NR%2!=0'
1
3
5
7
9
3.5.3 模式匹配符
~ 左边是否和右边匹配,包含关系
!~ 是否不匹配
范例
[root@centos8 ~]#awk -F: '$0 ~ /root/{print $1}' /etc/passwd
[root@centos8 ~]#awk -F: '$0 ~ "^root"{print $1}' /etc/passwd
[root@centos8 ~]#awk '$0 !~ /root/' /etc/passwd
[root@centos8 ~]#awk '/root/' /etc/passwd
[root@centos8 ~]#awk -F: '$3==0' /etc/passwd
[root@centos8 ~]#df | awk -F"[[:space:]]+|%" '$0 ~ /^\/dev\/sd/{print $5}'
5
1
92
[root@centos8 ~]#ifconfig eth0 | awk 'NR==2{print $2}'
10.0.0.8
3.5.4 逻辑操作符
与:&&,并且关系
或:||,或者关系
非:!,取反
范例:!取反
[root@centos8 ~]#awk 'BEGIN{print i}'
[root@centos8 ~]#awk 'BEGIN{print !i}'
1
[root@centos8 ~]#awk -v i=10 'BEGIN{print !i}'
0
[root@centos8 ~]#awk -v i=-3 'BEGIN{print !i}'
0
[root@centos8 ~]#awk -v i=0 'BEGIN{print !i}'
1
[root@centos8 ~]#awk -v i=abc 'BEGIN{print !i}'
0
[root@centos8 ~]#awk -v i='' 'BEGIN{print !i}'
1
范例
awk -F: '$3>=0 && $3<=1000 {print $1,$3}' /etc/passwd
awk -F: '$3==0 || $3>=1000 {print $1,$3}' /etc/passwd
awk -F: '!($3==0) {print $1,$3}' /etc/passwd
awk -F: '!($3>=500) {print $1,$3}' /etc/passwd
3.5.5 条件表达式(三目表达式)
selector?if-true-expression:if-false-expression
awk -F: '{$3>=1000?usertype="Common User":usertype="SysUser";printf "%-20s:%12s\n",$1,usertype}' /etc/passwd
3.6 模式PATTERN
PATTERN:根据pattern条件,过滤匹配的行,再做处理
3.6.1 空模式
- 如果未指定:空模式,匹配每一行
awk -F: '{print $1,$3}' /etc/passwd
3.6.2 /regular expression/
- /regular expression/:仅处理能够被模式匹配的行,需要用/ /括起来
[root@centos8 ~]#awk '/^UUID/{print $1}' /etc/fstab
[root@centos8 ~]#awk '!/^UUID/{print $1}' /etc/fstab
[root@centos8 ~]#df | awk '/^\/dev\/sd/'
/dev/sda2 104806400 4935924 99870476 5% /
/dev/sda3 52403200 398876 52004324 1% /data
/dev/sda1 999320 848572 81936 92% /boot
3.6.3 relational expression:关系表达式
- relational expression:关系表达式,结果为”真“才会被处理
真:如果未非0值,非空字符串
假:结果为空字符串或0值
[root@centos8 ~]#awk '1' /etc/passwd
[root@centos8 ~]#awk '!1' /etc/passwd
[root@centos8 ~]#awk '!0' /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
.......
[root@centos8 ~]#awk '1' /etc/issue
\S
Kernel \r on an \m
[root@centos8 ~]#awk '0' /etc/issue
[root@centos8 ~]#awk '"magedu"' /etc/issue
\S
Kernel \r on an \m
[root@centos8 ~]#awk '""' /etc/issue
[root@centos8 ~]#awk 'magedu' /etc/issue
[root@centos8 ~]#awk 'magedu' /etc/issue
[root@centos8 ~]#awk -v magedu=wang 'magedu' /etc/issue
\S
Kernel \r on an \m
[root@centos8 ~]#awk -v magedu="" 'magedu' /etc/issue
[root@centos8 ~]#awk -v magedu="0" 'magedu' /etc/issue
[root@centos8 ~]#awk -v magedu=0 'magedu' /etc/issue
[root@centos8 ~]#awk '"0"' /etc/issue
\S
Kernel \r on an \m
范例
seq 10 | awk 'i=0'
seq 10 | awk 'i=1'
seq 10 | awk 'i=!i'
seq 10 | awk '{i=!i;print i}'
seq 10 | awk '!(i=!i)'
seq 10 | awk -v i=1 'i=!i'
[root@centos8 ~]#seq 10 | awk 'i=0'
[root@centos8 ~]#seq 10 | awk 'i=1'
1
2
3
4
5
6
7
8
9
10
[root@centos8 ~]#seq 10 | awk 'i=1'
1
2
3
4
5
6
7
8
9
10
[root@centos8 ~]#seq 10 | awk 'i=0'
[root@centos8 ~]#seq 10 | awk 'i=!i'
1
3
5
7
9
[root@centos8 ~]#seq 10 | awk '!(i=!i)'
2
4
6
8
10
[root@centos8 ~]#seq 10 | awk -v i=1 'i=!i'
2
4
6
8
10
[root@centos8 ~]#seq 10 | awk -v i=0 'i=!i
1
3
5
7
9
[root@centos8 ~]#seq 10 | awk '{i=!i;print i}'
1
0
1
0
1
0
1
0
1
0
awk -F: 'i=1;j=1{print i,j}' /etc/passwd
Awk -F: '$3>=1000{print $1,$3}' /etc/passwd
awk -F: '$3<1000{print $1,$3}' /etc/passwd
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
[root@centos8 ~]#awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
wang /bin/bash
mage /bin/bash
[root@centos8 ~]#awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
root /bin/bash
wang /bin/bash
mage /bin/bash
3.6.4 line ranges:行范围
- line ranges:行范围
不支持直接用行号,但可以使用变量NR间接指定行号
/pat1/,/pat2/ 不支持直接给出数字格式
[root@centos8 ~]#seq 10 | awk 'NR>=3 && NR<=6'
3
4
5
6
[root@centos8 ~]#awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
3.6.5 BEGIN/END模式
- BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
awk -F : 'BEGIN {print "USER USERID"} {print $1":"$3} END{print "END FILE"}'/etc/passwd
awk -F: '{print "USER USERID";print $1":"$3} END{print "END FILE"}' /etc/passwd
awk -F: 'BEGIN{print "USER UID \n--------------- "}{print $1,$3}' /etc/passwd
awk -F: 'BEGIN{print "USER UID \n--------"}{print $1,$3}END{print "=========="}' /etc/p
3.7 条件判断 if-else
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else if(condition3)
{statement3}......else{statementN}
使用场景:对awk取得的整行或某个字段做条件判断
awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
awk '{if(NF>5) print $0}' /etc/fstab
awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
awk -F: '{if($3>=1000) printf "Common user: %s\n",$1; else printf "root or
Sysuser: %s\n",$1}' /etc/passwd
df -h|awk -F% '/^\/dev\/sd/{print $1}'| awk '$NF>=80{print $1,$5}'
df | awk -F"[[:space:]]+|%" '/^\/dev\/sd/{if($5>80)print $1,$5}'
[root@centos8 ~]#df | awk -F' +|%' '/^\/dev\/sd/{if($5>=10)print $1,$5}'
/dev/sda1 15
awk 'BEGIN{ test=100;if(test>90){print "very good"}
else if(test>60){ print "good"}else{print "no pass"}}'
3.8 条件判断switch
switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
3.9 循环while
while (condition) {statement;…}
条件为真,进入循环;条件为假,退出循环
使用场景
- 对一行内的多个字段逐一类似处理时使用
- 对数组中的各元素逐一处理时使用
#内置函数length()返回字符数,而非字节数
[root@centos8 ~]#awk 'BEGIN{print length("hello")}'
5
[root@centos8 ~]#awk 'BEGIN{print length("马哥教育")}'
4
[root@centos7 ~]#awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i); i++}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
[root@centos7 ~]#awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=10){print $i,length($i)}; i++}}' /etc/grub2.cfg
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
crashkernel=auto 16
net.ifnames=0 13
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
crashkernel=auto 16
net.ifnames=0 13
[root@centos8 ~]#awk 'BEGIN{ total=0;i=1;while(i<=100){total+=i;i++};print
total}'
5050
3.10 循环 do-while
do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
[root@centos8 ~]#awk 'BEGIN{ total=0;i=1;do{ total+=i;i++;}while(i<=100);print total}'
5050
3.11 循环for
for(expr1;expr2;expr3) {statement;…}
特殊用法:能够遍历数组中的元素
for(var in array) {for-body}
范例
[root@centos8 ~]#awk 'BEGIN{total=0;for(i=1;i<=100;i++){total+=i};print total}'
5050
[root@centos7 ~]#awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
linux16 7
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
性能比较
time (awk 'BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;};print total;}')
time (total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
time (for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
time (seq –s ”+” 10000|bc)
3.12 continue和break
continue中断本次循环
break 中断整个循环
continue [n]
break [n]
范例
[root@centos8 ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
2500
[root@centos8 ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i}print sum}'
1225
3.13 next
next可以提前结束对本行处理而直接进入下一行处理(awk自身循环)
[root@centos8 ~]#awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
nobody 65534
polkitd 998
gluster 996
rtkit 172
3.14 数组
awk数组为关联数组
array_name[index-expression]
范例
weekdays["mon"]="Monday"
index-expression
- 利用数组,实现k/v功能
- 可使用任意字符串,字符串要使用双引号括起来
- 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为空串
- 若要判断数组是否存在某元素,要使用”index in array“格式进行遍历
范例
[root@centos8 ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday
awk '!line[$0]++' dupfile
awk '{!line[$0]++;print $0, line[$0]}' dupfile
范例:判断数组索引是否存在
[root@centos8 ~]# awk 'BEGIN{array["i"]="x"; array["j"]="y" ; print "i" in array, "y" in array }'
1 0
[root@centos8 ~]#awk 'BEGIN{array["i"]="x"; array["j"]="y" ;if ("i" in array ) {print "存在"}else{print "不存在"}}'
存在
[root@centos8 ~]#awk 'BEGIN{array["i"]="x"; array["j"]="y" ;if ("abc" in array ) {print "存在"}else{print "不存在"}}'
不存在
若要遍历数组中的每个元素,要使用for循环
for(var in array) {for-body}
注意:var会遍历array的每个索引
[root@centos8 ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print i,weekdays[i]}}'
tue Tuesday
mon Monday
范例:显示主机的连接状态出现的次数
[root@centos8 ~]#awk 'NR!=1{print $1}' ss.log |sort |uniq -c
118 ESTAB
1 FIN-WAIT-1
11 LAST-ACK
[root@centos8 ~]#cat ss.log | sed -nr '1!s/^([^0-9]+) .*/\1/p'|sort |uniq -c
529 ESTAB
9 LISTEN
128 SYN-RECV
95 TIME-WAIT
[root@centos8 ~]#ss -ant | awk 'NR!=1{state[$1]++}END{for(i in state){print i,state[i]}}'
SYN-RECV 128
LISTEN 9
ESTAB 529
TIME-WAIT 95
[root@centos8 ~]#netstat -tan | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}'
LISTEN 9
SYN_RECV 126
ESTABLISHED 523
FIN_WAIT2 40
范例:显示连接的主机次数
[root@centos8 ~]#awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log
172.20.0.200 1482
172.20.21.121 2
172.20.30.91 29
172.16.102.29 864
172.20.0.76 1565
172.20.9.9 15
172.20.1.125 463
172.20.61.11 2
172.20.73.73 198
[root@centos8 ~]#awk '{ip[$1]++}END{for(i in ip){print ip[i],i}}' access_log |sort -nr| head -3
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
[root@centos8 ~]#awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log |sort -k2 -nr|head -3
172.20.116.228 4870
172.20.116.208 3429
172.20.0.222 2834
范例:封掉查看访问日志总连接次数超过1000次的IP
[root@centos8 ~]#awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){system("iptables -A INPUT -s "i" -j REJECT")}}}' nginx.access.log
范例:多维数组
[root@centos8 ~]#awk 'BEGIN{
> array[1][1]=11
> array[1][2]=12
> array[1][3]=13
> array[2][1]=21
> array[2][2]=22
> array[2][3]=23
> for (i in array)
> for (j in array[i])
> print array[i][j]
> }'
11
12
13
21
22
23
3.15 awk 函数
awk函数分为内置和自定义函数
3.15.1 常见内置函数
3.15.1.1 数值处理
rand() 返回0和1直接的随机数
srand() 配合rand()函数,生成随机数的种子
int() 返回函数
[root@centos8 ~]#awk 'BEGIN{srand();print rand()}'
0.790437
[root@centos8 ~]#awk 'BEGIN{srand();print rand()}'
0.283736
[root@centos8 ~]#awk 'BEGIN{srand();print rand()}'
0.948082
[root@centos8 ~]#awk 'BEGIN{srand();print rand()}'
0.371798
[root@centos8 ~]#awk 'BEGIN{srand(); for (i=1;i<=5;i++)print int(rand()*100)
}'
35
17
35
95
19
3.15.1.2 字符串处理
length([s]):返回指定字符串的长度
sub(r,s,[t]):对t字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换成s
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,…
范例
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
2008-08:08 08:08:08
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk '{sub(/:/,"-",$1);print $0}'
2008-08:08 08:08:08
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'
2008-08-08 08-08-08
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk '{gsub(/:/,"-",$0);print $0}'
2008-08-08 08-08-08
[root@centos8 ~]#netstat -tn | awk '/^tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
10.0.0.1 1
10.0.0.6 1
10.0.0.7 673
3.15.1.3 awk中可以调用shell命令
system('cmd')
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他都要用”“引起来
awk 'BEGIN{system("hostname")}'
awk 'BEGIN{score=100; system("echo your score is " score) }'
[root@centos8 ~]#netstat -tn | awk '/^tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count){if(count[i]>=10){system("iptables -A INPUT -s "i" -j REJECT")}}}
3.15.2 自定义函数
自定义函数格式
function name ( parameter, parameter, ... ) {
statements
return expression
}
范例
[root@centos8 ~]#cat func.awk
function max(x,y) {
x>y?var=x:var=y
return var
}
BEGIN{print max(a,b)}
[root@centos8 ~]#awk -v a=30 -v b=20 -f func.awk
30
3.16 awk脚本
将awk程序写成脚本,直接调用或执行
[root@centos8 ~]#cat passwd.awk
{if($3>=1000)print $1,$3}
[root@centos8 ~]#awk -F: -f passwd.awk /etc/passwd
nobody 65534
wang 1000
mage 1001
向脚本传递参数
awkfile var=value var2=value2... Inputfile
注意:在BEGIN过程中不可使用,直到首行输入完成以后,变量才可使用。可以通过-v参数,让awk在执行 BEGIN之前得到变量的值。命令行中每一个指定变量都需要一个-v参数
范例
[root@centos8 ~]#cat test2.awk
#!/bin/awk -f
{if($3 >=min && $3<=max)print $1,$3}
[root@centos8 ~]#chmod +x test2.awk
[root@centos8 ~]#./test2.awk -F: min=100 max=200 /etc/passwd
systemd-resolve 193
rtkit 172
pulse 171
qemu 107
usbmuxd 113
abrt 173
范例:检查出最近一个小时内访问nginx服务次数超过3次的客户端IP
[root@VM_0_10_centos ~]# cat check_nginx_log.awk
#!/usr/bin/awk -f
BEGIN {
beg=strftime("%Y-%m-%dT%H:%M",systime()-3600) ;
#定义一个小时前的时间,并格式化日期格式
end=strftime( "%Y-%m-%dT%H:%M",systime()-60) ;
#定义结束时间
#print beg;
#print end;
}
$4 > beg && $4 < end {#定义取这个时间段内的日志
count[$12]+=1;#利用ip当做数组下标,次数当做数组内容
}
END {
for(i in count){#结束从数组取数据代表数组的下标,也就是ip
if(count[i]>3) { #如果次数大于3次,做操作
print count [i]" "i;
#system("iptables -I INPUT -S”i”j DROP" )
}
}
}
#awk -F'"' -f check_nginx_log.awk /apps/nginx/logs/access.log
[root@VM_0_10_centos ~]# awk -F'"' -f check_nginx_log.awk /apps/nginx/logs/access_json.log
4 127.0.0.1
56 172.105.120.92
5 58.87.87.99
11 111.199.184.16