Shell脚本文本三剑客之awk

1 awk 介绍

  • AWK 是一种处理文本文件的语言,是一个强大的文本分析工具
  • 可以在无交互的模式下实现复杂的文本操作
  • 相较于sed常作用于一整个行的处理,awk则比较倾向于一行当中分成数个字段来处理,因为awk相当适合小型的文本数据。

1.1 awk 工作原理

逐行读取文本,默认以空格或 tab 键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。
sed 命令常用于一整行的处理,而awk 比较倾向于将一行分成多个"字段" 然后再进行处理。awk 信息的读入也是逐行读取的,执行结果可以通过 print 的功能将字段数据打印显示。在使用 awk 命令的过程中,可以使用逻辑操作符 “&&” 表示"与"、“||” 表示"或"、“!” 表示 “非”;还可以进行简单的数学运算,如 +、-、*、/、%、^ 分别表示加、减、乘、除、取余和乘方。

1.2 awk 命令的基本格式

命令格式
awk 选项 '模式或条件 {操作}' 文件1 文件2...
awk -f 脚本文件 文件1 文件2...

awk 常见的内建变量(可直接用)

FS列分割符。指定每行文本的字段分隔符,默认为空格或制表位。:与 “-F” 作用相同
NF当前处理的行的字段个数
NR当前处理的行的行号(序数)
$0当前处理的行的整行内容
$n(代表大于等于1的数字)当前处理行的第 n 个字段(第n列)
FILENAME被处理的文件名
RS行分隔符。awk 从文件上读取资料时,将根据 RS 的定义把资料切割成许多条记录,而 awk 一次仅读入一条记录,以进行处理。预设值是 ‘\n’

1.2.1 以行输出文本

在这里插入图片描述
例1:打印全部内容

[root@localhost awk]# awk '{print $0}' test1
[root@localhost awk]# awk '{print}' test1

在这里插入图片描述
例2:打印前三行

[root@localhost awk]# awk 'NR==1,NR==3 {print $0}' test1    

[root@localhost awk]# awk '(NR>=1)&&(NR<=3) {print}' test1  #输出连续的行

#输出第一行和第三行内容(输出不连续的行)
[root@localhost awk]# awk '(NR==1)||(NR==3) {print}' test1
[root@localhost awk]# awk '(NR>=1)||(NR<=3) {print}' test1

在这里插入图片描述
在这里插入图片描述
例3:取出ifconfig ens33里面的ip(第二行第二列)

[root@localhost awk]# ifconfig ens33
[root@localhost awk]# ifconfig ens33 |awk 'NR==2{print $2}'

在这里插入图片描述
例4:打印奇数行和偶数行

[root@localhost awk]# awk '(NR%2)==1{print}' test1
[root@localhost awk]# awk '(NR%2)==0{print}' test1

在这里插入图片描述
例5:字符串打印

[root@localhost awk]# awk '/root/ {print}' /etc/passwd   #包含root的行内容
[root@localhost awk]# awk '/^root/ {print}' /etc/passwd     #以root开头的行内容
[root@localhost awk]# awk '/bash$/ {print}' /etc/passwd    #以bash结尾的行内容

在这里插入图片描述

1.2.2 扩充:awk ‘BEGIN{…};{…};END{…}’ 文件

  • 在 awk 处理文本前会执行 BEGIN 模式里的命令
  • 中间的 {…} 是真正用于处理文件的命令操作
  • 在 awk 处理完文件后才会执行 END{…} 模式里的命令操作
[root@localhost awk]# awk 'BEGIN {x=0};/\/bin\/bash$/{x++};END {print x}' /etc/passwd   #统计以/bin/bash 结尾的行数,等同于grep -c "/bin/bash$"

[root@localhost awk]# awk 'BEGIN {x=0};/\/bin\/bash$/{print;x++;print x};END {print x}' /etc/passwd 

BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作;awk 再处理指定的文本,之后再执行END模式中指定的动作,END{}语句块中,往往会放入打印结果等语句

在这里插入图片描述

1.2.3 以字段(列)输出文本

例1

全部
[root@localhost awk]# awk -F ':' '{print $0}' /etc/passwd   -F指定分隔符分隔符

打印第一列
[root@localhost awk]# awk -F ':' '{print $1}' /etc/passwd

打印第一列和第三列
[root@localhost awk]# awk -F ':' '{print $1,$3}' /etc/passwd
[root@localhost awk]# awk -F ':' 'BEGIN{FS=":"};{print $1,$3}' /etc/passwd

在这里插入图片描述
例2:在/etc/passwd中打印UID号大于500 的字段和小于等于500的字段

[root@localhost awk]# awk -F : '$3>500 {print $1,$3}' /etc/passwd    #-F指定以冒号为分隔符,UID号大于500

[root@localhost awk]# awk -F : '!($3>500) {print $1,$3}' /etc/passwd  #UID号小于等于500

使用相关语句操作时,需要再加一层{},整条语句看做一个操作命令
[root@localhost awk]# awk -F : '{if($3>500) {print $1,$3}}' /etc/passwd

在这里插入图片描述
在这里插入图片描述

1.2.4 三元运算符

(条件表达式)?(A表达式或者值):(B表达式或者值) 三元运算符  [条件表达式] &&  A  || 
条件表达式成立为真时会取:号前面的A的值
条件表达式不成立为假时会取:号后面的B的值
[root@localhost awk]# awk -F : '{max=($3>=$4)?$3:$4;{print max,$1}}' /etc/passwd
#($3>$4)?$3:$4;三元运算符,如果第3个字段的值大于等于第4个字段的值,则把第3个字段的值赋给max,否则第4个字段的值赋给max

在这里插入图片描述

1.2.5 $NF、$n~、$n==、$n!=

$NF            代表最后一个字段
$n~"字符串"       ~代表字段包含某个字符串的作用
$n=="字符串"       ==代表字段为某个字符串的作用
$n!="字符串"       !=代表字段不为某个字符串的作用
[root@localhost awk]# awk -F : '{print NR,$0}' /etc/passwd   #输出每行内容和行号,每处理完一条记录,NR值加1

[root@localhost ~]# awk -F ":" '$7~"/bash"{print $1}' /etc/passwd    #输出以冒号分隔且第7个字段中~(包含)/bash的行的第1个字段

[root@localhost ~]# awk -F ":" '($1~"root") && (NF==7){print $1,$2}' /etc/passwd    #输出第1个字段中包含root且有7个字段的行的第1、2个字段

[root@localhost ~]# awk -F ":" '($7!="/bin/bash") && ($7!="/sbin/nologin"){print}' /etc/passwd    #输出第7个字段既不为/bin/bash,也不为/sbin/nologin的所有行

[root@localhost ~]# awk -F ":" '{print $1,$NF}' /etc/passwd  #输出以冒号分隔且第1个字段和最后1个字段

在这里插入图片描述

1.2.6 OFS 输出内容的列分隔符

[root@localhost awk]# echo "A B C D"
A B C D
[root@localhost awk]# echo "A B C D" | tr " " "|"
A|B|C|D
[root@localhost awk]# echo "A B C D" | sed 's/ /\|/g'
A|B|C|D
[root@localhost awk]# echo "A B C D" | awk 'BEGIN{OFS="|"};{print $0}'
A B C D
[root@localhost awk]# echo "A B C D" | awk 'BEGIN{OFS="|"};{$1=$1;print $0}'
A|B|C|D
[root@localhost awk]# echo "A B C D" | awk 'BEGIN{OFS="|"};{$2=$2;print $0}'
A|B|C|D

在这里插入图片描述

1.3 高级用法1—通过管道、双引号调用shell命令

例1:统计行数

[root@localhost awk]# echo $PATH
[root@localhost awk]# echo $PATH |awk 'BEGIN{RS=":"};{print NR,$0}' 

[root@localhost awk]# echo $PATH |awk 'BEGIN{RS=":"};{print NR,$0};END{print NR}'
 #统计以冒号分隔的文本段落数,END{}语句块中,往往会放入打印结果等语句

在这里插入图片描述

[root@localhost awk]# awk -F: '/bash$/{print | "wc -l"}' /etc/passwd
#调用wc -l命令统计使用bash的用户个数,等同于grep -c "bash$"/etc/passwd

[root@localhost awk]# grep -c "bash$" /etc/passwd

在这里插入图片描述
例2:查看当前内存使用百分比

[root@localhost awk]# free
[root@localhost awk]# free | awk '/Mem:/ {print $3/$2}'

[root@localhost awk]# free | awk '/Mem:/ {print $3/$2*100}'

[root@localhost awk]# free | awk '/Mem:/ {print int($3/$2*100)}'

[root@localhost awk]# free | awk '/Mem:/ {print int($3/$2*100)"%"}'      #查看当前内存使用百分比

在这里插入图片描述
例3:CPU的空闲率,输出top里id的值

[root@localhost awk]# top -b -n 1  #一次输出
[root@localhost awk]# top -b -n 1 | awk -F, '/Cpu/{print $4}' | awk '{print $1}'

[root@localhost awk]# top -b -n 1 | awk -F, '/Cpu/{print $4}' | awk '{print int ($1)}'

[root@localhost awk]# top -b -n 1 | awk -F, '/Cpu/{print $4}' | awk '{print int ($1) "%"}'

在这里插入图片描述
在这里插入图片描述

1.4 高级用法2—awk数组特性

例1

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

[root@localhost awk]# awk 'BEGIN{a["abc"]=10;a["xyz"]=20;print a["abc"]}'    #字符串要带" "
[root@localhost awk]# awk 'BEGIN{a["abc"]=10;a["xyz"]=20;print a["xyz"]}'   

[root@localhost awk]# awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a)print i,a[i]}'     #i代表数组的下标值

在这里插入图片描述
例2

[root@localhost awk]# awk '{a[1]++;print a[1]}' test1
[root@localhost awk]# awk '{a[$1]++};END{for(i in a){print i,a[i]}}' test1
$1第一个字段的值
[]里代表列的值
把列的值作为数组的下标去看待
然后去匹配行的内容,匹配一次加1
通过for循环,打印出下标的值和出现的次数

在这里插入图片描述

1.5 日期—date

例1

[root@localhost awk]# date
[root@localhost awk]# date +"%F"
[root@localhost awk]# date +"%Y%m%d"  #当前时间

[root@localhost awk]# date +"%Y%m01"   #本月第一天

[root@localhost awk]# date -d "$(date -d "1 month" +"%Y%m01") -1 day" +"%Y%m%d"    #当前月最后一天
[root@localhost awk]# date -d "$(date -d "1 month" +"%Y%m01")" +"%Y%m%d"   #下个月第一天

[root@localhost awk]# date -d "$(date +"%Y%m01") -1 day" +"%Y%m%d"     #上个月最后一天
[root@localhost awk]# date -d "$(date +"%Y%m01") -3 day" +"%Y%m%d"     #上个月倒数第三天

在这里插入图片描述
例2

[root@localhost awk]# date -d "2 day ago" +"%Y%m%d"    #2天前的时间
[root@localhost awk]# date -d "10 day ago" +"%Y%m%d"   #10天前的时间

[root@localhost awk]# date -d "10 second 
[root@localhost awk]# date -d "10 second ago" +"%Y%m%d %H:%M:%S"   #10秒前

在这里插入图片描述
例3

[root@localhost awk]# cat /proc/uptime

[root@localhost awk]# awk -F. '{print $1}' /proc/uptime

[root@localhost awk]# date -d "$(awk -F. '{print $1}' /proc/uptime) second ago" +"%Y%m%d %H:%M:%S"   #服务器重启的时间

在这里插入图片描述

1.6 案例

通过脚本分析 /var/log/secure 查看哪些主机在暴力破解本服务,如果统计出密码验证失败超过三次就把IP加入到黑名单中 /etc/hosts.deny
awk sort uniq -c

awk '/Failed passwdord/{print $11}' /var/log/secure |sort -rn | uniq -c | awk '$1>3 {print "sshd:"$2}' >>/etc/hosts.deny 
先筛选11列包含Failed passwdord的
然后排序、去重
最后把筛选出超过三次的加入到黑名单/etc/hosts.deny中

或者
awk '/Failed passwdord/{a[$11]++};END{for(i in a){print i,a[i]}}' /var/log/secure

在这里插入图片描述

在这里插入图片描述
方法一:
在这里插入图片描述
方法二:
在这里插入图片描述

总结

1、awk ‘BEGIN{…};{…};END{…}’ 文件

  • 在 awk 处理文本前会执行 BEGIN 模式里的命令
  • 中间的 {…} 是真正用于处理文件的命令操作
  • 在 awk 处理完文件后才会执行 END{…} 模式里的命令操作

2、三元运算符

(条件表达式)?(A表达式或者值):(B表达式或者值) 三元运算符  [条件表达式] &&  A  || 
条件表达式成立为真时会取:号前面的A的值
条件表达式不成立为假时会取:号后面的B的值

3

BEGIN{FS="指定分隔符"};   #FS:列分隔符 OFS:输出内容的列分隔符
awk -F '指定分隔符' '条件{print $1,$NF}'
NR==n,NR==m     #n~m
(NR>=n) && (NR<=m) 
/字符串+正则/

4

sn> <==对比数值
$NF              代表最后一个字段
$n~"字符串"       ~代表字段包含某个字符串的作用
$n=="字符串"       ==代表字段为某个字符串的作用
$n!="字符串"       !=代表字段不为某个字符串的作用

5、日期date

date +"%Y%m%d"     #当前时间 
date +"%Y%m01"    #当前月的第一天
date -d "$(date -d "1 month" +"%Y%m01") -1 day" +"%Y%m%d"    #当前月最后一天
date -d "$(date -d "1 month" +"%Y%m01")" +"%Y%m%d"   #下个月第一天
date -d "$(date +"%Y%m01") -1 day" +"%Y%m%d"     #上个月最后一天
date -d "$(date +"%Y%m01") -3 day" +"%Y%m%d"     #上个月倒数第三天
date -d "2 day ago" +"%Y%m%d"    #2天前的时间
date -d "$(awk -F. '{print $1}' /proc/uptime)second ago" +"%Y%m%d  %H:%M:%S"    #服务器重启的时间
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值