Shell编程--awk

发布时间:2024年01月15日

1.awk简介

  • awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。可以在命令行中使用,但更多是作为脚本来使用。
  • awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行操作。
  • 如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。
  • awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。
  • awk是行处理器:优势在于处理庞大文件时不会出现内存溢出或是处理缓慢的问题。
  • awk处理过程:依次对每一行进行处理,然后输出,默认分隔符是空格或者tab键

2.awk的形式语法格式

awk [options] 'commands' filenames
-F:对于每次处理的内容,可以指定一个自定义的分隔符,默认的分隔符是空白字符(空格或 tab 键 )

3.awk工作原理

awk -F":" '{print $1,$3}' /etc/passwd
1.awk使用一行作为输入,并将这一行赋给变量$0,每一行可称作为一个记录,以换行符结束
2.然后,行被空格分解成字段,每个字段存储在已编号的变量中,从$1开始
3.awk如何知道空格来分隔字段的呢?因为有一个内部变量FS来确定字段分隔符,初始时,FS赋为空格或者是tab
4.awk打印字段时,将以设置的方法,使用print函数打印,awk在打印的字段间加上空格,因为$1,$2间有一个,逗号。逗号比较特殊,映射为另一个变量,成为输出字段分隔符OFS,OFS默认为空格
5.awk打印字段时,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程持续到处理文件结束。
command:BEGIN{} {} END{} filename
? 行处理前的动作 行内容处理的动作 行处理之后的动作 文件名
?

BEGIN{}和END{} 是可选项
BEGIN{}:读入文本之前要操作的命令。(也可以设置变量,取值可以不加$)
{}:主输入循环(用的最多),读入文件之后擦操作的命令;如果不读入文件都可以不用写。
END{}:文本全部读入完成之后执行的命令。

[root@localhost ~]# awk 'BEGIN{ print 1/2} {print "ok"} END{print "----"}' /etc/hosts
?//或者 cat /etc/hosts | awk 'BEGIN{print 1/2} {print "ok"} END{print "----"}'
0.5
ok
ok
----

4.记录与字段相关内部变量

awk 按记录处理:一行是一条记录,因为awk默认以换行符分开的字符串是一条记录。(默认\n换行符:记录分隔符)
字段:以字段分割符分割的字符串 默认是单个或多个“ ” tab键。
?awk中的变量
$0表示整行NF统计字段的个数/统计列的列数$NFnumber finally,表示最后一列的信息 (用的最多)RS输入记录分隔符ORS输出记录分隔符NR打印记录行号(用的最多)FNR可以分开,按不同的文件打印行号FS输入字段分隔符,默认为一个空格OFS输出的字段分隔符,默认为一个空格FILENAMEFILENAME 文件名 被处理的文件名称$1$1第一个字段,$2第二个字段,以此类推…

5.实战

5.1.FS(输入字段分隔符)----一般简写为-F(属于行处理前)

?注:如果-F不加默认为空格区分!

[root@localhost ~]# cat /etc/passwd | awk 'BEGIN{FS=":"} {print $1,$2}' 
//或者 awk -F':' '{print $1,$2}' /etc/passwd
root x
bin x
daemon x
....
[root@localhost ~]# cat /etc/passwd | awk -F":" '{print $1,$2}'
root x
bin x
daemon x
....

5.2.OFS(输出字段分隔符)

[root@localhost ~]# cat /etc/passwd | awk 'BEGIN{FS=":";OFS=".."} {print $1,$2}'      #OFS  输出的字段分隔符,默认为一个空格。 
root..x
bin..x
daemon..x
...

//创建两个文件
[root@localhost ~]# vim a.txt
love
love.
loove
looooove
[root@localhost ~]# vim file1.txt
isuo
IPADDR=192.168.246.211
hjahj123
GATEWAY=192.168.246.1
NETMASK=255.255.255.0
DNS=114.114.114.114

5.3.NR 表示记录编号,在awk将行做为记录,该变量相当于当前行号,也就是记录号

[root@localhost ~]# awk '{print NR,$0}' a.txt file1.txt
1 love
2 love.
3 loove
4 looooove
5  
6 isuo
7 IPADDR=192.168.246.211
8 hjahj123
9 GATEWAY=192.168.246.1
10 NETMASK=255.255.255.0
11 DNS=114.114.114.114

5.4.FNR:表示记录编号,在awk将行做为记录,该变量相当于当前行号,也就是记录号(#会将不同文件分开)

[root@localhost ~]# awk '{print FNR,$0}' a.txt file1.txt
1 love
2 love.
3 loove
4 looooove
5  
1 isuo
2 IPADDR=192.168.246.211
3 hjahj123
4 GATEWAY=192.168.246.1
5 NETMASK=255.255.255.0
6 DNS=114.114.114.114

FR和FNR的区别:
NR:代表总的记录(行)数,在所有文件中是连续不断的。
FNR:仅代表当前文件中的记录(行)数,不同文件从1开始计数。

5.5.RS(输入记录分隔符)备注:自定义换行符,匹配到指定字符后替换成换行符

//创建一个文件
[root@localhost ~]# cat a.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
tang:x:1000:1000:tang:/home/tang:/bin/bash
ntp:x:38:38::/etc/ntp:/sbin/nologin
nginx:x:1001:1001::/home/nginx:/bin/bash
root:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologin
?
[root@localhost ~]#  awk 'BEGIN{RS="bash"} {print $0}'  a.txt
root:x:0:0:root:/root:/bin/
?
bin:x:1:1:bin:/bin:/sbin/nologin
tang:x:1000:1000:tang:/home/tang:/bin/
?
ntp:x:38:38::/etc/ntp:/sbin/nologin
nginx:x:1001:1001::/home/nginx:/bin/
?
root:x:0:0:root:/root:/bin/
bin:x:1:1:bin:/bin:/sbin/nologin

5.6.ORS(输出记录分隔符)

//对刚才的文件进行修改
[root@localhost ~]# vim passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

//输入记录符为bash,输出记录符为换行
[root@localhost ~]#  awk 'BEGIN{RS="bash";ORS="----"} {print $0}'  a.txt
root:x:0:0:root:/root:/bin/----
bin:x:1:1:bin:/bin:/sbin/nologin
tang:x:1000:1000:tang:/home/tang:/bin/----
ntp:x:38:38::/etc/ntp:/sbin/nologin
nginx:x:1001:1001::/home/nginx:/bin/----
root:x:0:0:root:/root:/bin/----bin:x:1:1:bin:/bin:/sbin/nologin

5.7.NF:统计列的个数

[root@localhost ~]# cat /etc/passwd | awk -F":" '{print NF}'
7
7
7
7

5.8.$NF:打印最后一列

[root@localhost ~]# cat /etc/passwd | awk -F":" '{print $NF}'
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin

练习1:将文件合并为一行

[root@localhost ~]# cat /etc/passwd | awk 'BEGIN{ORS="" } {print $0}'

练习2:把一行内容分成多行

//首先创建一个文件
[root@localhost ~]# vim d.txt
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# cat d.txt | awk 'BEGIN{RS=":"} {print $0}'
root
x
0
0
root
/root
/bin/bash

6.关系运算符号

6.1.实现字符串的完全相等需要使用 ==

字符串需要使用双引号
!= 表示不等于,取反

[root@localhost ~]# awk -F":"  '$NF=="/bin/bash"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
tang:x:1000:1000:tang:/home/tang:/bin/bash
nginx:x:1001:1001::/home/nginx:/bin/bash
// == 后面的字符串不加引号就无法打印出来
?
[root@localhost ~]# awk -F":" '$1 != "root"' /etc/passwd
[root@localhost ~]# awk -F":" '$NF!="/sbin/nologin"'  /etc/passwd

6.2.比较表达式:

  • 比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。
  • 比较表达式使用关系运算符,用于比较数字与字符串。关系运算符有
    < 小于 x<y
    > 大于 x>y
    <= 小于或等于 x<=y
    == 等于 x==y
    != 不等于 x!=y
    >= 大于等于 x>=y

示例

[root@localhost ~]# awk -F":"  '$3 == 0 ' /etc/passwd
root:x:0:0:root:/root:/bin/bash
?
[root@localhost ~]# awk -F":"  '$3 < 2 ' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
?
[root@localhost ~]# awk -F":" '$3<2' passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
?
[root@localhost ~]# awk -F":" '$3<=2' 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
?
[root@localhost ~]# awk -F":" '$3>100' passwd
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
tang:x:1000:1000:tang:/home/tang:/bin/bash
?
[root@localhost ~]# awk -F":" '$3>=1000' passwd
tang:x:1000:1000:tang:/home/tang:/bin/bash

6.3.算术运算:+,-,*,/,%(模: 取余), (幂:23)

可以在模式中执行计算,awk都将按浮点数方式执行算术运算

[root@localhost ~]# awk -F: '$3 * 10 > 1000' /etc/passwd
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
tang:x:1000:1000:tang:/home/tang:/bin/bash
nginx:x:1001:1001::/home/nginx:/bin/bash
?
[root@localhost ~]# awk -F":" '$3  * 10 >=10000' passwd
tang:x:1000:1000:tang:/home/tang:/bin/bash
  • 逻辑操作符和复合模式
    && 逻辑与,相当于 并且
    ||逻辑或,相当于 或者
    ! 逻辑非 ,取反
[root@localhost ~]# awk -F":" '$NF=="/bin/bash"  && $3 >=15' /etc/passwd
tang:x:1000:1000:tang:/home/tang:/bin/bash
nginx:x:1001:1001::/home/nginx:/bin/bash
?
?
[root@localhost ~]# awk -F":" '$NF=="/bin/bash" ||  $3 >=15' /etc/passwd
root:x:0:0:root:/root:/bin/bash
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
tang:x:1000:1000:tang:/home/tang:/bin/bash
ntp:x:38:38::/etc/ntp:/sbin/nologin
nginx:x:1001:1001::/home/nginx:/bin/bash

6.4.常见使用

1.打印一个文件中的第一行的第2列和第3列

[root@localhost ~]# cat /etc/passwd | awk -F: 'NR==1 {print $2,$3}'
x 0

2.打印指定行指定列的某个字符

//获取内存可使用空间
[root@localhost ~]# free -h|awk 'NR==2 {print $4}'
2.5G
?
[root@localhost ~]# cat /etc/passwd | awk -F: 'NR==2  {print $1}'
bin
?
//获取根分区的使用量
[root@localhost ~]# df -Th|awk 'NR==6 {print $5}'
48G

3.统计一个文件的行数、列数

//打印行数
[root@localhost ~]# cat /etc/passwd | awk '{print NR}'
?
//打印列数
[root@localhost ~]# cat /etc/passwd | awk -F: '{print NF}'

4.awk和if条件判断结合使用(使用最广)
监控告警脚本使用if判断

[root@localhost ~]# df -Th|awk 'NR==6 {print $6}'|awk -F% '{print $1}'
5

//判断根分区当前使用率
[root@localhost ~]# vim disk.sh
#!/bin/bash
root_used=`df -Th|awk 'NR==6 {print $6}'|awk -F% '{print $1}'`
if [[ $root_used -gt 90 ]]; then
  echo "警报!服务器根分区使用率超过90%,当前使用率为${root_used}%"
else
  echo "当前根分区使用率${root_used}%,一切正常!"
fi
//往/root中写入测试文件
[root@localhost ~]# dd if=/dev/zero of=/root/text.txt count=44 bs=1G    //大小根据磁盘空间
[root@localhost ~]# wacth -n1 bash disk.sh    //另一个终端查看
//判断当前cpu使用率,当空闲率小于20%时告警
//查看当前cpu的空闲率
[root@localhost ~]# top -b -n1|grep -i cpu|awk -F,'NR==1 {print $4}' |awk '{print $1}'
100.0

参数解释
n 设置退出前屏幕刷新的次数
b 将top输出编排成适合输出到文件的格式,可以使用这个选项创建进程日志

//当cpu空闲率小于20%就告警(说明使用率超过了80%)
#!/bin/bash
cpu_free=$(top -b -n1|grep -i cpu|awk -F','  'NR==1 {print $4}' |awk '{print $1}')
alarm_value=20.0
if [[ $(echo "$cpu_free > $alarm_value" | bc) -eq  1 ]];then
  echo "当前服务器CPU空闲率为:${cpu_free}%,一切正常!"
else
  echo "警报!服务器CPU使用率超过80%,当前CPU空闲率为${cpu_free}%!"
fi
?
//或将bc去掉也可以,不过只能比较整数
#!/bin/bash
cpu_free=$(top -b -n1|grep -i cpu|awk -F','  'NR==1 {print $4}' |awk -F"." '{print $1}')
alarm_value=20
if [[ "$cpu_free > $alarm_value" ]];then
  echo "当前服务器CPU空闲率为:${cpu_free}%,一切正常!"
else
  echo "警报!服务器CPU使用率超过80%,当前CPU空闲率为${cpu_free}%!"
fi
?
//bc是一种用于高精度计算的命令行计算器工具,支持数学运算、函数计算、字节单位换算等。
bc -eq 1  解释:
[root@localhost ~]# echo "29.9 <=29.99"|bc
1   #正确为1
[root@localhost ~]#  echo "29.9 >= 29.99"|bc
0   #错误为0
[root@localhost ~]# yum -y install bc
?
//正常情况的脚本:
[root@localhost ~]# bash cpu.sh
当前服务器CPU空闲率为:97.1%,一切正常!
?
//使用压测工具,将cpu的使用率拉满
//安装压测工具
yum install stress sysstat  -y
?
//模拟cpu运行
stress --cpu 2 --timeout 600
?
//执行完之后再去执行脚本,查看是否会报错
[root@localhost ~]# bash cpu.sh
警报!服务器CPU使用率超过80%,当前CPU空闲率为0.0%!
?
?//查询CPU占用情况
[root@localhost ~]# mpstat -P ALL 5
Linux 3.10.0-1160.66.1.el7.x86_64 (localhost.localdomain)       20230716_x86_64_        (2 CPU)
?
085335秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
085340秒  all  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
0853400  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
0853401  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
#-P ALL:显示所有的逻辑处理器(CPU)的CPU使用和负载信息
#5:显示信息的间隔为 5 秒。
?
//或者使用top/htop查看
[root@localhost ~]# top -b -n1|grep -i cpu
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
#使用top查看cpu的可用率为0.0
?
?
//判断当前内存可用空间,低于0.5G时告警
[root@localhost ~]# free -h|awk 'NR==2 {print $4}'|awk -FG '{print $1}'
2.4
?
//当内存可用空间少于0.5G时告警
#!/bin/bash
free=$(free -h|awk 'NR==2 {print $7}'|awk -FG '{print $1}')
alarm_value=0.5
if [[ $(echo "$free > $alarm_value" | bc) -eq  1 ]];then
  echo "当前服务器内存可用空间为:${free}G,一切正常!"
else
  echo "警报!服务器内存可用空间少于0.5G,当前内存的可用空间为:${free}"
fi
?
//正常情况下执行的脚本
[root@localhost ~]# bash free.sh
当前服务器内存可用空间为:3.5G,一切正常!
?
//使用压测工具将内存值拉高,并执行告警脚本
[root@localhost ~]# stress --vm 10 --vm-bytes 1024M --timeout 30s
stress: info: [94472] dispatching hogs: 0 cpu,0 io,10 vm,0 hdd

参数解释
–vm 指定测试类型,此处为 memory 测试。
10 指定创建 10 个虚拟用户。每个虚拟用户都会占用指定大小的内存空间。
–vm-bytes 1024M 指定每个虚拟用户分配的内存大小,此处为 1024MB。
–timeout 30s 指定测试运行时间,此处为 30 秒。
?

[root@localhost ~]# bash free.sh
(standard_in) 1: illegal character: M
警报!服务器内存可用空间少于0.5G,当前内存的可用空间为:84M

5.在awk中使用for循环

//每行打印两遍
[root@localhost ~]# awk '{for(i=1;i<=2;i++) {print $0}}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

6.5.经典案例

UV与PV统计
PV:即访问量,也就是访问您商铺的次数;
例如:今天显示有300 PV,则证明今天你的商铺被访问了300次。
UV:即访问人数,也就是有多少人来过您的商铺; #需要去重
例如:今天显示有50 UV,则证明今天有50个人来过你的商铺。
切割nginx的日志,统计PV/UV,出现次数最多的url等各种切割统计

1.根据访问IP统计UV

[root@localhost ~]# cat access.log | awk '{print $1}' |sort |uniq -c | wc -l
//uniq:去重
//-c:统计每行连续出现的次数

2.更具访问ip统计PV

[root@localhost ~]# cat access.log | awk '{print $1}' |wc -l
或者是url
[root@localhost ~]# cat access.log | awk '{print $7}' |wc -l

3.查询访问最频繁的URL

[root@localhost ~]# cat access.log | awk '{print $7}'|sort | uniq -c |sort -rn -k1

4.查询访问最频繁的IP

[root@localhost ~]# cat access.log | awk '{print $1}'|sort | uniq -c |sort -n -k 1 -r | more
文章来源:https://blog.csdn.net/m0_62396418/article/details/135595973
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。