shell脚本中awk应用,数组的定义使用

1、awk的基础应用

1.1,概念

除了使用 sed 命令,Linux 系统中还有一个功能更加强大的文本数据处理工具,就是 awk。它诞生于 20 世纪 70 年代末期,这也许是它影响了众多 Linux 用户的原因之一。
AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。awk命名: Aho、Weingberger 和 Kernighan三个人的姓的缩写。
awk也是一个数据处理工具!相较于 sed 常常作用于一整个行的处理, awk 则比较倾向于一行当中分成数个字段来处理。
和 sed 命令类似,awk 命令也是逐行扫描文件(从第 1 行到最后一行),寻找含有目标文本的行,如果匹配成功,则会在该行上执行用户想要的操作;反之,则不对行做任何处理。

1.1.2,awk

在linux上常用的是gawk,awk是gawk的链接文件
在这里插入图片描述
awk 的强大之处在于commands,它由2部分组成,分别为匹配规则和执行命令,如下所示:
‘匹配规则{执行命令}’
awk命令的完整格式:awd [-F field-separator] ‘匹配规则{执行命令}’ filename
这里的匹配规则,和 sed 命令中的匹配规则部分作用相同,用来指定执行命令可以作用到文本内容中的具体行(匹配条件),可以使用字符串(比如 /demo/,表示查看含有demo字符串的行)或者正则表达式指定。另外需要注意的是,整个commands是用单引号(’’)括起,而其中的执行命令部分需要用大括号({})括起来。
举个简单的例子:
[root@localhost ~]# awk '/^KaTeX parse error: Expected group after '^' at position 41: …est.txt 在此命令中,/^̲/ 是一个正则表达式,功能是匹配文本中的空白行,同时可以看到,执行命令使用的是 print 命令,此命令经常会使用,它的作用很简单,就是将指定的内容进行输出。因此,整个命令的功能是,如果 test.txt 有 N 个空白行,那么执行此命令会输出 N 个 Blank line。
注:在 awk 程序执行时,如果没有指定执行命令,则默认会把匹配的行输出;如果不指定匹配规则,则默认匹配文本中所有的行。

1.1.4,'匹配规则{执行命令}'

任何awk语句都是由’匹配规则{执行命令}‘组成,一个awk中可以有多个语句。匹配规则决定执行命令的执行条件。
例如上面举的例子中’/^KaTeX parse error: Expected group after '^' at position 26: …Blank line"}',/^̲/就是匹配规则,print就是执行命令,当文件中有匹配/^$/条件的行是就会执行pirnt命令。

1.1.5,匹配规则(即执行条件):

一般使用关系表达式作为条件。这些关系表达式非常多,具体参考下表:
条件类型 条 件 说 明
awk保留字 BEGIN 在awk程序一开始,尚未读取任何数据之前执行。BEGIN 后的动作只在程序开始时执行一次
awk保留字 END 在awk程序处理完所有数据,即将结束时执行。END 后的动作只在程序结束时执行一次
关系运算符 > 大于
< 小于
>= 大于等于
<= 小于等于
== 等于。用于判断两个值是否相等。如果是给变童赋值,则使用"=”
!= 不等于
匹配表达式 ~(匹配) value ~ /regexp/ 如果value匹配/regexp/,则返回真
!~(不匹配) value !~ /regexp/ 如果value不匹配/regexp/,则返回真
正则表达式 /正则表达式/ 如果在“//”中可以写入字符,则也可以支持正则表达式,如:/root/表示匹配含有root的行。
逻辑运算符 && 逻辑与
|| 逻辑或
例如:
[root@localhost ~]# awk -F: ‘7   / b a s h 7 ~ /bash7 /bash/ {print $1}’ /etc/passwd
判断7 ( 第 7 个 数 据 字 段 ) 的 值 是 否 匹 配 正 则 表 达 式 / b a s h 7(第7个数据字段)的值是否匹配正则表达式/bash77/bash/
[root@localhost ~]# awk -F: ‘7 !   / b a s h 7 !~ /bash7! /bash/ {print $1}’ /etc/passwd
判断7 ( 第 7 个 数 据 字 段 ) 的 值 是 否 不 匹 配 正 则 表 达 式 / b a s h 7(第7个数据字段)的值是否不匹配正则表达式/bash77/bash/

1.1.6,awk 使用数据字段变量

前面说过,在 awk 中,默认的字段分隔符是任意的空白字符(例如空格或制表符)。 在文本行中,每个数据字段都是通过字段分隔符划分的(-F选项指定的分隔符)。awk 在读取一行文本时,会用预定义的字段分隔符划分每个数据字段。如/etc/passwd文件中可以将“:”当做字段分隔符,共划分成7个数据字段。
awk 的主要特性之一是其处理文本文件中数据的能力,它会自动给一行中的每个数据字段分配一个变量。
默认情况下,awk 会将如下变量分配给它在文本行中发现的数据字段:
$0 代表整个文本行;
$1 代表文本行中的第 1 个数据字段;
KaTeX parse error: Unexpected character: '' at position 21: …本行中的第 2 个数据字段; ̲n 代表文本行中的第 n 个数据字段。
所以在下面的例子中,awk 程序读取文本文件,只显示第 1 个数据字段的值:
[root@localhost ~]# cat data1.txt
One line of test text.
Two lines of test text.
Three lines of test text.
[root@localhost ~]# awk ‘{print $1}’ data1.txt //把文件中每行的空格当做分隔符
One
Two
Three
本例中用$1字段变量来表示第1个数据字段。当然,如果你要读取采用了其他字段分隔符的文件,可以用 -F 选项手动指定。

1.1.7,执行命令(动作action):

awk的执行命令在大括号{ }内指明。动作大多数用来打印(即print指令),但是还有些更长的代码诸如i f和循环语句及循环退出结构。如果不指明采取动作,awk将打印出所有浏览出来的记录。
动作(Action):
格式化输出(print);
流程控制语句(if、while、for等);
例如:显示passwd文件中第1个第6个字段的信息
在这里插入图片描述
1.1.8,awk中的BEGIN和END

语法:awk [options] ‘BEGIN{ print “start” } 匹配规则{ commands } END{ print “end” }’ filename
其中:BEGIN END是AWK的关键字,因此必须大写;这两个部分开始块和结束块是可选的
BEGIN模块:BEGIN 的执行时机是"在 awk 程序一开始,尚未读取任何数据之前"。一旦BEGIN后的动作执行一次,当awk开始从文件中读入数据时,BEGIN 的条件就不再成立,所以BEGIN定义的动作只能被执行一次。通过BEGIN开始块我们可以用来设置变量,设置标题。
例如:
在这里插入图片描述
#这里定义了两个动作
#第一个动作使用BEGIN条件,所以会在读入文件数据前打印"print username and loginshell" (只会执行一次)
#第二个动作会在条件满足时打印文件的第1个字段和第7个字段
END模块:END也是awk的保留字,不过刚好和 BEGIN 相反。END 是在 awk 程序处理完所有数据,即将结束时执行的。END 后的动作只在程序结束时执行一次。
例如:
输出结尾输入"The End",这并不是文档本身的内容,而且只会执行一次
在这里插入图片描述
1.1.9,AWK工作过程:
在这里插入图片描述
在这里插入图片描述
通过上面我们可以知道;AWK它工作过程
1.如果BEGIN块存在,awk执行它指定的actions。
2.awk从输入文件中读取一行,称为一条输入记录。(如果输入文件省略,将从标准输入读取),awk将读入的记录分割成多个字段,将第1个字段放入变量$1中,第2个字段放入$2,以此类推。$0表示整条记录。
3、把当前输入记录与awk中’匹配规则{执行命令}'中的“匹配规则”比较,看是否匹配,如果相匹配,就执行对应的‘执行命令’。如果不匹配,就跳过对应的执行命令。
4、awk读取输入的下一行,继续重复步骤2和3,这个过程一直持续,直到awk读取到文件尾。
5、当awk读完所有的输入行后,如果存在END,就执行相应的actions。
例如:显示最近登录系统的用户,要求只显示用户名和登录源
使用last命令可以查看最近登录的用户信息。如下图所示:
在这里插入图片描述
使用awk命令抽取用户名和IP区域的数据
在这里插入图片描述

1.2,awk的变量

1.2.10,awk自定义变量
自定义变量:用户自己定义的变量,有两种形式
1、-v varname=value 变量名区分字符大小写
例如:统计用户数量:
在这里插入图片描述
2、在program中直接定义,以下定义了3个自定义变量,其实形式像编程语言一样,定义的时候用分号。打印变量跟之前一样,用逗号隔开,注意,不需要用美元符号。在这里插入图片描述
3、也可以引用命令行定义的变量
在这里插入图片描述
范例:
统计某个目录(如/root)下的文件占用的字节数(以MB显示):在这里插入图片描述
注:之前的{}里都是只有一个print语句,其实print只是一个语句,而{}可以有多个语句,以;号隔开。

1.2.11,awk内置变量(预定义变量)

awk除了可以自定义变量外,awk还提供一些内置量,常用的内置标量如下:
$n 当前记录(当前行)的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段
$0 这个变量包含执行过程中当前行的文本内容
FILENAME 当前输入文件的名
FS 字段分隔符(默认是任何空格)
NF 表示字段数,在执行过程中对应于当前的字段数
NR 表示记录数,在执行过程中对应于当前的行号
FNR 各文件分别计数的行号
说明:
练习文件内容:
[root@localhost ~]# cat ceshi1.txt
wangwu 20 man
zhangsan 22 woman
lisi 23 woman
[root@localhost ~]# cat ceshi2.txt
chenzhe 20 man
xiaoming 22 woman
lier 23 woman
例1:NF:打印出每行有多少列:
在这里插入图片描述
如何显示最后两列的值呢?
分析:NF变量表示每行字段数,所以NF的值就是每行最后一个字段,NF减1就是倒数第二个字段。
注:引用NF变量,需要用美元符号
在这里插入图片描述
例2:NR:每一行的行号:
在这里插入图片描述
例3:FNR:awk支持多文件扫描,如果采用NR, 下一个文件的行序号会接着上一个文件,FNR就会单独统计
在这里插入图片描述
在这里插入图片描述
例4:FS:分隔符
范例1:分隔符的使用
用法:-F fs 其中fs是指定输入分隔符,fs可以是字符串或正则表达式;分隔符默认是空格
常见的写法: -F: -F, -F[aA]
在这里插入图片描述
范例2:指定多个分隔符
在这里插入图片描述

1.3,实例演示

1.3.12,awk范例
范例1:提取网卡的IP地址
在这里插入图片描述
范例2:关系运算符的使用
在这里插入图片描述
范例3:打印passwd文件中用户UID小于10的用户名和它登录使用的shell
[root@localhost ~] # awk -F: ‘$3<10{print 1 " < = = = = = > " 1"<=====>"1"<=====>"NF}’ /etc/passwd
范例4-:打印系统中能够正常登录的普通用户
[root@localhost ~]# awk -F: ‘$3>=1000 && $NF=="/bin/bash"{print 1 , 1,1,NF}’ /etc/passwd
范例5:统计当前内存的使用率
在这里插入图片描述
说明:printf命令与print命令类似,用于显示输出的,只不过printf命令可以按照指定的格式显示输出。
printf命令格式:printf “打印格式” 显示内容
其中:%2.f就是打印格式,表保留小数后两位,f代表浮点数
**

2,awk控制语句

**
**

2.1,if语句

**
if (条件) print
if(条件){print}else{print}
if(条件){print}else if(条件){print}else{print}
2.1.2,范例1:
[root@localhost ~]# awk -F: ‘{if($3<1000) {print “system_user=”$1} else {print “program_user=”$1}}’ /etc/passwd
2.1.3,范例2:
统计分区使用率,输出超过15%的分区信息
[root@localhost ~]# df -hT | awk -F"[ %]+" ‘/^/dev/ {if($6>15)print $1,$6"%"}’
在这里插入图片描述
说明: -F"[ %]+"表示将空格或%当做分隔符。
if语句使用的地方===》对awk来说,要对取得的整行或某个字段做条件判断
2.2,while循环
语句:while(条件){语句} 如果条件为“真”进入循环,条件为“假”退出循环
在进行运算结果统计时,可以使用符号+=,意思是说我们可以把增加的结果赋值给符号的左边的变量,对哪个域操作就把哪个域写在符号的右边,如Total+=$3
2.2.4,范例1:
统计成绩
[root@localhost ~]# cat score.txt
姓名 性别 城市 科目 语文 数学 英语 总分 平均分
马茵茵 女 上海 文科 85 94 70 249 83.00
刘俊 男 上海 理科 76 80 83 239 79.67
刘婷婷 女 广州 理科 83 88 81 252 84.00
汤洁冰 女 广州 理科 67 88 52 207 69.00
余小灵 男 天津 理科 93 90 87 270 90.00
吴日新 男 南京 文科 99 90 85 274 91.33
[root@localhost ~]# awk ‘{total=total+$5}END{print "YuWen score:"total}’ score.txt
YuWen score:503
[root@localhost ~]# awk ‘{total+=KaTeX parse error: Expected 'EOF', got '}' at position 2: 5}̲END{print "YuWe…i;i++}; print total}’ b.txt
34
59
57
说明:while语句使用的地方===》在awk中对一行内容中的多个字段一个个处理。

2.3,for循环

语法:for(变量赋值;条件;迭代){命令}
[root@localhost ~]# awk ‘{total=0;for(i=1;i<=NF;i++){total+=$i}; print total}’ b.txt
34
59
57
特殊作用:它能够用来遍历数组中的元素
语法:for (var in array){语句}

2.4偶数(next)

打印奇数或偶数行
[root@localhost ~]# awk ‘NR%2==0{print NR,$0}’ /root/score.txt
2 马茵茵 女 上海 文科 85 94 70 249 83.00
4 刘婷婷 女 广州 理科 83 88 81 252 84.00
6 余小灵 男 天津 理科 93 90 87 270 90.00

2.5,数组

2.5.6,定义
数组是一个包含一系列元素的集合。
格式如下:
abc[1]=”xiaohong”
abc[2]=”xiaolan”
解释:
abc :为数组名称
[1]、[2]:为数组元素下标,可以理解为数组的第1个元素、数组的第2个元素
”xiaohong”、”xiaolan”: 元素内容

2.5.7,数组变量赋值的格式

var[index]=element
说明:var====>是数组名
index===>是关联数组的下标
element===>是数组的元素值
2.5.7.3,数字做数组下标:
array[1]=”sun”
array[2]=”kai”
我们在引用数组变量的时候,必须要包含它的下标值,然后通过下标值来提取它相对应的元素值
[root@localhost ~]# awk 'BEGIN{

test[“a”]=“Mon”
test[“b”]=“Tue”
test[“c”]=“Wor”
print test[“b”]
}’
显示结果:
Tue
也可以写成:
#awk ‘BEGIN{test[“a”]=“Mon”;test[“b”]=“Tue”;test[“c”]=“Wed”;print test[“b”]}’

2.5.8,遍历数组中的元素

若要遍历数组中的每个元素,可以使用for循环:
for(var in array){print array[var]}
说明: for循环在每次循环时会将数组array的一个下标值赋给变量var,然后去执行大括号中的语句。还有一个需要注意的地方就是这个变量var中存储的是下标值而不是数组的元素值。我们可以把这个变量当作是数组的下标,然后来提取出对应元素值
[root@localhost ~]# awk 'BEGIN{

test[“a”]=“Mon”
test[“b”]=“Tue”
for(i in test)
{print "Index:“i,”-----value:"test[i]}
}’
Index:a -----value:Mon
Index:b -----value:Tue

2.5.9,删除数组元素

[root@localhost ~]# awk ‘BEGIN{test[1]=“a”;test[2]=“b”;for(i in test){print "Index:“i,”=====value:"test[i]}; delete test[2];print “---------”;for(i in test){print "Index:“i,”=====value:"test[i]}}’
Index:1 =====value:a
Index:2 =====value:b

Index:1 =====value:a

2.5.10,数组应用范例

array[“index”]++ 每循环一次这个索引所对应的元素值加1(初始值默认是0)
它经常用来统计某个东西出现的次数,可以这样表示:
2.5.10.1、范例1:
统计Listen和Estableshed出现的次数
在这里插入图片描述
2.5.10.2,范例2:统计相同的网站出现的次数
测试文件:
[root@localhost ~]# cat c.txt
http://www.163.com
http://www.163.com
http://www.163.com
http://www.baidu.com
http://www.baidu.com
http://www.baidu.com
http://www.baidu.com
http://www.cnblogs.com
http://www.qq.com
http://www.163.com
http://www.baidu.com
http://www.baidu.com
http://www.qq.com
http://www.163.com
http://www.baidu.com
[root@localhost mnt]# awk -F"[/]+" ‘{print $2}’ c.txt | sort
www.163.com
www.163.com
www.163.com
www.baidu.com
www.baidu.com
www.baidu.com
www.baidu.com
www.cnblogs.com
www.qq.com
[root@localhost mnt]# awk -F"[/]+" ‘{print $2}’ c.txt |sort|uniq -c
5 www.163.com
7 www.baidu.com
1 www.cnblogs.com
2 www.qq.com
注:
sort命令用于将文本文件内容加以排序
uniq命令用于检查及删除文本文件中重复出现的行列,一般与sort命令结合使用。
也可以通过下面的操作统计每个网站出现的次数:
[root@localhost ~]# awk -F"[/]+" ‘{times[$2]++}END{for(i in times){print i,times[i]}}’ c.txt
www.qq.com 2
www.cnblogs.com 1
www.baidu.com 7
www.163.com 5


版权声明:本文为qq_52194329原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。