文本三剑客

文本三剑客

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值