三剑客awk

1.awk基础

awk是由Alfred Aho 、Peter Weinberger 和 Brian Kernighan这三个人创造的,awk由这个三个人的姓氏的首个字母组成。
awk早期是在unix上实现的,所以,我们现在在linux的所使用的awk其实是gawk,也就是GNU awk,简称为gawk,awk还有一个版本,New awk,简称为nawk,但是linux中最常用的还是gawk。

1.1awk是什么
awk是一个报告生成器,它拥有强大的文本格式化的能力,这就是专业的说法。

你可能不理解所谓的报告生成器中的"报告"是什么,你可以把"报告"理解为"报表"或者"表格",也就是说,我们可以利用awk命令,将一些文本整理成我们想要的样子,比如把一些文本整理成"表"的样子,然后再展示出来,刚才概念中提到的"文本格式化的能力",也就是这个意思,其实这样说可能还是不太容易理解,不用着急,当你看到后面的"示例"时,自然会明白awk所擅长的"文本格式化"能力是什么。

awk其实是一门编程语言,它支持条件判断、数组、循环等功能。所以,我们也可以把awk理解成一个脚本语言解释器。

1.2三剑客
grep 、sed、awk被称为linux中的"三剑客"。

我们总结一下这三个"剑客"的特长。

grep 更适合单纯的查找或匹配文本

sed 更适合编辑匹配到的文本

awk 更适合格式化文本,对文本进行较复杂格式处理

2.akw实操

2.1
这就是最简单的语法了
awk [options] ‘program’ file1 , file2 ,

从字面意思上看action指的就是动作 awk擅长文本格式化,将文本格式化以后的文本输出,所以awk最常用的动作就是print和printf,因为awk要把格式化完成后的文本输出啊,所以,这两个动作最常用。
awk [options] ‘Pattern{Action}’ file

下面展示一下不加任何参数的应用
在这里插入图片描述
上图中的示例没有使用到options和pattern,上图中的awk ‘{print $5}’,表示输出df的信息的第5列,$5表示将当前行按照分隔符分割后的第5列,不指定分隔符时,默认使用空格作为分隔符,细心的你一定发现了,上述信息用的空格不止有一个,而是有连续多个空格,awk自动将连续的空格理解为一个分割符了,是不是比cut命令要简单很多,这样比较简单的例子,有利于我们开始了解awk。

awk是逐行处理的,逐行处理的意思就是说,当awk处理一个文本时,会一行一行进行处理,处理完当前行,再处理下一行,awk默认以"换行符"为标记,识别每一行,也就是说,awk跟我们人类一样,每次遇到"回车换行",就认为是当前行的结束,新的一行的开始,awk会按照用户指定的分割符去分割当前行,如果没有指定分割符,默认使用空格作为分隔符。

从上图我们可以看出我们利用awk过滤除了第一例的内容,那么疑问来了df -hT | awk ‘{print $1}’ $1是什么意思呢
在这里插入图片描述

我们发现awk过滤除了第一列,第二列,第三列的内容 那么awk都是根据列来过滤的
在这里插入图片描述

0 表 示 显 示 整 行 , 0 表示显示整行 , 0NF表示当前行分割后的最后一列( 0 和 0和 0NF均为内置变量)

我们下面测试一下,我们使用$0做测试,我们发现$0的效果与df -ht的命令是一模一样的
在这里插入图片描述

N F 则 表 示 分 割 最 后 一 列 , 比 如 d f − h T 查 看 的 一 共 是 7 列 , 使 用 NF 则表示 分割最后一列,比如df -hT 查看的一共是7列,使用 NFdfhT7使NF的值就是 7 , 那 么 如 果 我 们 想 过 滤 倒 数 第 二 行 也 可 以 7,那么如果我们想过滤倒数第二行也可以 7(NF-1)
在这里插入图片描述

当然awk这么强大的命令,也可以一次查看多行,使用逗号隔开要输出的多个列,如下,一次性输出第一列,第二列,倒数第二列
在这里插入图片描述

当我们指定无效的列时,也不会做任何输出,我们试一下,如果$8会怎么样
答案是什么都不会显示
在这里插入图片描述

2.2 awk字符与列拼接

创建个文本测试一下吧

[root@bogon ~]# echo zbc > test.txt
[root@bogon ~]# cat test.txt
zbc

测试

[root@bogon ~]# awk '{print "hahaha",$1,"666"}' test.txt 
hahaha zbc 666

但是像$1这种内置变量是不能加双引号的,否则会被当成普通的字符来使用

[root@bogon ~]# awk '{print "hahaha","$1","666"}' test.txt 
hahaha $1 666

2.3 BEGIN模式和ENG模式

用简单的话来说BEGIN代表的在什么操作之前,ENG模式则代表在什么操作之后

我们看一下怎么用吧

表示在开始处理text.txt文本之前,先处理 BEGIN中的内容

[root@bogon ~]# awk 'BEGIN{print "abc","zbc"}  {print $1}' test.txt 
abc zbc
zbc
也可以不指定文本,awk还是会先执行BEGIN中的内容,打印完成后,发现没有文本可以处理,于是只打印了BEGIN的内容
[root@bogon ~]# awk 'BEGIN{print "abc","zbc"} '
abc zbc

我们先测试一下END的使用,END使用跟BEGIN的使用方法一样,只是显示位置不同
类似于报表,有表头,表内容,表尾

[root@bogon ~]# awk 'BEGIN{print "abc","zbc"}  END{print "1121"} {print $1}' test.txt 
abc zbc
zbc
1121

相信聪明的小伙伴已经看懂了 ,END模式就是在处理完所有指定的文本之后,需要指定的动作
在这里插入图片描述

3.AWK分隔符

3.1 AWK有哪些分隔符
awk的默认分割符是空格,但是,这样描述并不精确,因为,awk的分隔符还分为两种,“输入分隔符” 和 “输出分隔符” 。

3.1.1 输入分隔符
输入分隔符比较容易理解,当awk逐行处理文本的时候,以输入分隔符为准,将文本切成多个片段,默认使用空格,但是,如果一段文字中没有空格,我们可以指定以特定的文字或符号作为输入分割符,比如下图中的例子,我们指定使用"#"作为输入分隔符。
在这里插入图片描述
如果想使用awk过滤#号应该怎么做呢

使用-F选项来指定#号为输入分隔符,通过#号分割

[root@bogon ~]# awk -F## '{print $1,$2}' test.txt 
zbc 123
abc 123

使用-v选项,能够通过设置内部环境变量的方式,指定awk的输入分隔符,awk内置变量FS可以用于指定输入分隔符,但是在使用变量时,需要使用-v选项,用于指定对应的变量,比如 -v FS=’#’,

[root@bogon ~]# awk -v FS=## '{print $1,$2}' test.txt 
zbc 123
abc 123

-F 用于指定分隔符
-v 用于设置变量的值

3.1.2 输出分隔符
那么什么是输出分隔符呢?当awk为我们输出每一列的时候,会使用空格隔开每一列,其实,这个空格,就是awk的默认的输出分隔符
输出分割符的意思就是:当我们要对处理完的文本进行输出的时候,以什么文本或符号作为分隔符。

我们可以使用awk的内置变量OFS来设置awk的输出分隔符,使用变量的时候要结合-v参数使用
这里因为之前创建的文本的分隔符为两个#作分割,所以需要指定-F选项,如果只在文本使用了一个#号,则直接使用OFS变量即可

[root@bogon ~]# awk -v OFS="," -F##  '{print $1,$2}' test.txt 
zbc,123
abc,123
[root@bogon ~]# awk -v OFS="," -v FS=##  '{print $1,$2}' test.txt 
zbc,123
abc,123

3.1.3 合并使用 输入分隔符和输出分隔符

非常简单,一看就懂了

[root@bogon ~]# awk -v FS=## '{print $1,$2}' test.txt 
zbc 123
abc 123
[root@bogon ~]# awk -v FS=## '{print $1$2}' test.txt 
zbc123
abc123

4. AWK格式化

利用awk中的printf动作,即可对文本进行格式化输出,printf动作的用法与printf命令的用法非常相似,只是有略微的不同而已,不过,我们还是从最简单的示例开始看起,首先对比一下print动作与printf动作的区别,示例如下

[root@bogon ~]# awk -v FS=## '{print $1$2}' test.txt 
zbc123
abc123
[root@bogon ~]# awk -v FS=## '{printf $1$2}' test.txt 
zbc123abc123[root@bogon ~]# 

与终端操作的printf结果是一样的,不会自动换行,p不会输出换行符,默认会将文本输出在第一行

4.1 这里先说一下print和printf的区别:
print和printf的主要区别就在于这里,我们看效果一目了然,这里使用echo代替print

[root@bogon ~]# echo  "a b c"
a b c
只能用,换行符来换行,那如果有100行呢 
## -e 代表可以使用转义字符
[root@bogon ~]# echo -e "a \nb \nc"
a 
b 
c

那么printf如何换行呢 “%s\n“ 代表传参,即a b c 被当做参数传入printf,printf就会把"%s\n"中的%s替换成abc,于是,abc就变成了我们指定的格式"abc\n",最终printf输出的就是格式化后的"abc\n"。

[root@bogon ~]# printf "a b c"
a b c[root@bogon ~]# 
[root@bogon ~]# printf "%s\n"  a b c
a
b
c
[root@bogon ~]# printf "%s\n"  abc
abc

4.2
我们试一下变量会怎么样呢?为什么会报错呢?
原因是在使用printf动作时,指定的"格式"与列($1)之间需要用"逗号"隔开,而使用printf命令时,指定的格式与传入的文本不需要使用"逗号"隔开
在这里插入图片描述

[root@bogon ~]# awk  -v FS=## '{printf "%s\n" , $1}' test.txt 
zbc
abc

这又是为什么?

[root@bogon ~]# awk   'BEGIN{printf "%s\n"  ,  1,2,3,4,5}' 
1

在使用printf命令,只需指定一次格式替换符,执行多次也可以完成要求
但是在awk中,格式替换符的数量与传入的参数要相同,格式替换符的数量=格式化的参数的数量

[root@bogon ~]# awk   'BEGIN{printf "%s\n%s\n%s\n%s\n%s\n"  ,  1,2,3,4,5}' 
1
2
3
4
5

4.3

这是为什么?
因为awk本身负责文本切割,printf动作负责格式化文本,双剑合璧了。

[root@bogon ~]# awk   -v FS=## '{printf "第一列 %s\n" , $1}' test.txt 
第一列 zbc
第一列 abc

解决办法

[root@bogon ~]# awk   -v FS=## 'BEGIN{printf "%s\t %s\n" , "第一列","第二列" } {printf "%s\t  %s\n" , $1,$3}' test.txt 
第一列   第二列
zbc       haha
abc       xixi

小练习一下

[root@bogon ~]# awk -v FS=: 'BEGIN{printf "%-10s\t %s\t  %-10s\t  %-20s\t  %-20s\t %s\n" , "注册名","password","UID","GID","用户名","家目录"} {printf "%-10s\t %s\t  %-10s\t  %-20s\t  %-20s\t %s\n" , $1,$2,$3,$4,$5,$6}' /etc/passwd

因为有些名字太长就搞得对不上了 无妨 看懂语法就行了
在这里插入图片描述

注意点
在awk中使用printf动作时,需要注意以下3点。

1)使用printf动作输出的文本不会换行,如果需要换行,可以在对应的"格式替换符"后加入"\n"进行转义。

2)使用printf动作时,“指定的格式” 与 “被格式化的文本” 之间,需要用"逗号"隔开。

3)使用printf动作时,"格式"中的"格式替换符"必须与 “被格式化的文本” 一一对应。

5.awk模式(Pattern)之一

awk [options] ‘Pattern {Action}’ file1 file2 ···

对于options(选项)而言,我们使用过-F选项,也使用过-v选项。

对于Action(动作)而言,我们使用过print与printf,之后的文章中,我们还会对Action进行总结。

对于Pattern(模式)而言,我们在刚开始学习awk时,就介绍了两种特殊模式,BEGIN模式和END模式,但是,我们并没有详细的介绍"模式"是什么,怎么用,而此处,我们将详细的介绍一下awk中的模式。

模式可以比喻成条件与数据库的where的意思一样是条件的意思,awk是逐行处理文本的,也就是说,awk会先处理完当前行,再处理下一行,如果我们不指定任何"条件",awk会一行一行的处理文本中的每一行,如果我们指定了"条件",只有满足"条件"的行才会被处理,不满足"条件"的行就不会被处理。

当awk进行逐行处理的时候,会把pattern(模式)作为条件,判断将要被处理的行是否满足条件,是否能跟"模式"进行匹配,如果匹配,则处理,如果不匹配,则不进行处理。

搞一个测试文本
在这里插入图片描述

这里做了个简单的测试,NF是内置变量
第一行有两列,第二行有四列,第三行有三列
应该已经有人看出来了 如果被处理的行正好有*列字段,那么被处理的行则满足"条件"

[root@bogon ~]# awk  -v FS=# '{print $1,$2,$3,$4}' test2.txt 
abc 1   
def 2 3 4
iii 7 7 
[root@bogon ~]# awk  -v FS=# 'NF==3 {print $1,$2,$3,$4}' test2.txt 
iii 7 7  
[root@bogon ~]# awk  -v FS=# 'NF==2 {print $1,$2,$3,$4}' test2.txt 
abc 1   
[root@bogon ~]# awk  -v FS=# 'NF==4 {print $1,$2,$3,$4}' test2.txt 
def 2 3 4

==表示比较符号当时也可以使用大于小于,或者以组合的方式,这些都会可以被允许的

[root@bogon ~]# awk  -v FS=# 'NF<=3 {print $1,$2,$3,$4}' test2.txt 
abc 1   
iii 7 7  
[root@bogon ~]# awk  -v FS=# 'NF>=3 {print $1,$2,$3,$4}' test2.txt 
def 2 3 4
iii 7 7  
[root@bogon ~]# awk  -v FS=# 'NF>3 {print $1,$2,$3,$4}' test2.txt 
def 2 3 4
[root@bogon ~]# awk  -v FS=# 'NF<3 {print $1,$2,$3,$4}' test2.txt 
abc 1   

当然也可以匹配字符串

[root@bogon ~]# cat test3.txt
abc 123 iuy ddd
8ua 456 auv ppp 7y7
123 666
[root@bogon ~]# awk '$1==123 {print $0}' test3.txt 
123 666

使用的"模式"都有一个共同点,就是上述"模式"中,都使用到了关系表达式(关系操作符),比如 ==,比如<=,比如>,当经过关系运算得出的结果为"真"时,则满足条件(表示与指定的模式匹配),满足条件,就会执行相应的动作,而上例中使用到的运算符都是常见的关系运算符,我们就不解释了,那么awk都支持哪些关系运算符呢?

关系运算符含义用法示例
<小于x < y
<=小于等于x <= y
==等于x == y
!=不等于x != y
>=大于等于x >= y
>大于x > y
~与对应的正则匹配则为真x ~ /正则/
!~与对应的正则不匹配则为真x !~ /正则/

如下三类"模式"
1、空模式(什么模式也没有,直接执行)

2、关系运算模式(上图)

3、BEGIN/END模式(执行的先后顺序)

6.awk模式(Pattern)正则模式与行范围模式

根据上面我们已经学会了
1、空模式

2、关系运算模式

3、BEGIN/END模式

awk的另外两种常用模式,正则模式与行范围模式

6.1 正则模式

正则模式,正则模式其实肯定与正则表达式有关系,可以将模式理解为条件,顾名思义正则模式也就是以正则作为条件进行匹配

怎么样才能匹配到这行内容,我们用grep很简单因为grep默认就是去寻找行内容的,从而将整行的内容给列出来。awk默认从行中寻找列,将匹配到的字符,以列的方式显示出来。

在这里插入图片描述

  • 下面我们看一下两种方法的不同之处,首先是用grep过滤出这行

    是不是非常简单呢?
    在这里插入图片描述

  • 那么怎么才能用awk实现与grep一样的效果呢?

在这里插入图片描述

 在理解awk的正则模式之前首先我们看下格式图

在这里插入图片描述

  • awk命令在使用正则表达式时,将正则表达式放入了"/ /"中。
  • 这就是我们今天要介绍的"正则模式",在使用"正则模式"时,文本行如果能够被正则表达式匹配到,就会执行对应的动作,如果没有被正则匹配到,则不会执行对应的动作,而上例中,对应的动作就是{print
    $0},也就是打印整行,所以,上例中的grep命令与awk命令所实现的效果是完全相同的,那么你可能会问,既然效果完全相同,为什么还要使用awk呢?似乎grep更加简单一些,没错,上例中,grep是更加简单一些,但是不要忘了,awk有自己的优势,就是格式化能力,那么,我们换一个场景,可能使用awk就会更加实用了

在这里插入图片描述

1 这条语句也主要分为了两个部分,一个部分是使用了BEGIN打印出表头,第二部分使用正则表达式筛选除了符合条件的内容
2.第一部分其实上部分已经说过了,所以直接忽略,第二部分分为了四个部分
从/etc/passwd以正则的方式匹配到以mysql开头的用户
使用变量FS=":"对文本进行分割
取出需要的列,格式化出去
结合BEGIN模式生成表格,提高可读性

我知道大家都明白了,不过要在啰嗦一点需要注意的点,与grep一样在使用"//"需要使用转义符,否则会报错,就不列出错误的了,直接来一遍格式

这里为什么要使用转义符?其实原因也很简单,因为与正则的格式出现了冲突。
在这里插入图片描述

除此之外,还要注意以下两点

1、当在awk命令中使用正则模式时,使用到的正则用法属于"扩展正则表达式"

2、当使用 {x,y} 这种次数匹配的正则表达式时,需要配合–posix选项或者–re-interval选项。

下面还是给大家举例子吧,进行重复匹配
##可能是升级了,但是如果语句没错,确认匹配不到,请使用–posix选项或者–re-interval选项。
在这里插入图片描述
6.2 行范围模式

在了解行范围模式之前请务必先了解正则模式

那么在了解行范围模式之前我们首先去看一个例子,方便我们去理解行范围模式

在这里插入图片描述
在这里插入图片描述
如上图所示,从被正则1匹配到的行开始,到被正则2匹配到的行结束。意思就是说比如“ awk ‘/Kevin/,/aa/{print $0}’ test1.txt” ,他会先匹配Kevin,也就是从第五行开始匹配,匹配到Kevin再去匹配aa,从到aa之后就不会再往后执行,执行范围是5-8行的内容。

但是,你可能会有这样的需求,你不想依靠正则表达式去匹配行的特征,你只是想单纯的打印出从X行到Y行之间的所有行。
NR是内置变量表示行号NR>=3 && NR<=6 的意思就是说行号大于3 但是小于6 也就是筛选出3-6行中的内容
在这里插入图片描述
在这里插入图片描述

其他
  其实,在学习"关系表达式模式"时,有一个"关系运算符"需要与"正则模式"配合使用,它就是"~"

还记得我们之前总结的一些常用的关系运算符吗,我们来回顾一下。

在这里插入图片描述
统计404的连接

意思简单我们来拆分理解一下awk ‘($9 ~/404/)’ /etc/httpd/logs/access_log 当$9也就是状态码的行以正则的方式匹配等于404的时候,那么我就显示/etc/httpd/logs/access_log 所有内容(显示内容为匹配到404的行),我们在通过管道符来过滤那些使我们需要的信息,sort是让显示的内容美观,整齐,标准化,增加可读性
在这里插入图片描述
到目前为止,我们已经认识了awk的模式,模式可以总结为如下5种。

1、空模式

2、关系运算模式

3、正则模式

4、行范围模式

5、BEGIN/END模式

7.awk动作

最好已经了解了一些基本的开发语法,比如,if、if…else、for、while等,否则在阅读时 有可能遇到障碍。
在这里插入图片描述
上图中,我们将动作拆分成了两个部分。

红线标注为第一部分:最外侧的括号,即"{ }"。

蓝线标注为第二部分:“print $0”

在之前的示例中,我们一直把上图中的两个部分当做一个整理去理解,但是现在,我们要把它们分开去理解。

其实,这两个部分都可以被称之为"动作",只不过它们是不同"类型"的动作而已。

"print"属于"输出语句"类型的动作,顾名思义,"输出语句"类型的动作的作用就是输出、打印信息,没错,"print"与"printf"都属于"输出语句"类型的动作。

“{ }“其实也可以被称之为"动作”,只不过,”{ }"属于"组合语句"类型的动作,顾名思义,"组合语句"类型的动作的作用就是将多个代码组合成代码块。

可能你还是不太了解组合语句,那我们就开始一个小实验!

可以看到正常我们进行输出动作的时候{print $1,$2} 会分成两列进行打印,但是区分别执行打印动作的话,会合并成一列。
在这里插入图片描述

如上图所示,我们使用了两个大括号"{ }",它们属于"组合语句"类型的动,它们分别将两个print括住,表示这两个print动作分别作为两个独立的个体,如下图所示。
在这里插入图片描述

也就是说,我们可以这样理解,上图中一共有4个"动作",两对大括号,两个print,但是上图中,每个大括号中只有一个动作,而我们说过,“组合语句"的作用是将多个代码或多个动作组合成代码块,组合后的代码块被当做一个整体,那么,我们能不能把上图中的两个print动作组合成一个整体呢?
在这里插入图片描述
如上图所示,我们只使用了一个大括号,将两个print动作组合成了一个整体,当我们把多个动作(多段代码)组合成一个代码块的时候,每段动作(每段代码)之间需要用分号”;"隔开,如下图所示。
在这里插入图片描述

除了print这种"输出语句"能够被称之为动作以外,像"{ }"这种"组合语句"也能被称之为动作,只不过它们的类型不同,功能也不同。

那么,除了"输出语句"与"组合语句"以外,还有其他种类的动作吗?

必须的,我们现在就来认识另一种动作,它就是"控制语句"。

如果你有过任何一种编程语言的开发经验,你都会非常容易理解"条件判断",条件判断无非就是条件成立,则执行对应的代码,条件不成立,则不执行对应的命令,没错,在编程语言中,通常使用如下语法结构进行条件判断,也就是编程语法中的 if 条件判断语句。

if(条件)
{
语句1;
语句2;
...
}

7.1 if判断
在awk中,我们同样可以使用if这种语法进行条件判断,只不过,上例中的语法结构是由"多行"组成,而在命令行中使用awk时,我们可以将上例中的"多行"语句写在"一行"中,示例如下。
在这里插入图片描述
"if(NR == 1)"中的NR为awk的内置变量,NR为行号之意,所以,"if(NR == 1)"表示行号为1时,条件成立。
"if(NR == 1){ print $0 }"表示行号为1是满足条件,条件满足时,打印整行,换句话说就是只打印第一行。

你可能会纠结,为什么最外侧还需要有一层大括号呢?
没有为什么,就是要这样写,否则会报错。如果你非要一个理由,那么我们可以这样理解,所有动作的最外侧必须用"{ }“括起。你可能还是会纠结,if语句的语法结构中也包含大括号啊,那么它属于"组合语句"吗?虽然它的语法结构中也包含大括号,但是我们仍然把if语句称之为"控制语句”,或者我们可以这样理解,“控制语句"中包含"组合语句”。

if语句中的大括号中,也可以执行多个动作,把多个代码段当做一个整体,也就是说,如果if所对应的条件成立,则执行if的大括号中的所有命令
在这里插入图片描述

上例表示,如果行号为1,则满足条件,就会执行if对应的大括号中的所有代码,而大括号中,有两个print动作,当条件成立时,这两个print动作都会被执行,当条件不成立时,这两个动作都不会执行。根据之前学过的内容可能你已经想到了他为什么会分行,因为匹配成功后,先执行$1在执行$2

上例中,"if"对应的大括号中有多条语句,所以"if"语法中的大括号不能省略,但是,如果"if"对应的大括号中只有一条命令,那么"if"对应的大括号则可以省略,示例如下。
在这里插入图片描述

如上图所示,当"if"对应的大括号中只有一条命令时,对应的大括号可以省略,但是需要注意,如果条件成立之后,需要执行多条语句,那么"if"对应的大括号则不能省略。

在这里插入图片描述
上图中的用法为awk的"模式"的用法,而我们今天所介绍的用法为awk的"动作"的用法,虽然两者在语法上有所区别,但是达到的目的相同的。

编程语言中,除了"if"之外,还有"if…else…"或者"if…else if…else"这样的语法,awk中也有这样的用法。
"if…else…"的语法如下:

if(条件)
{
语句1;
语句2;
...
}
else
{
语句1;
语句2;
...
}

"if…else if…else"的语法如下:

if(条件1)
{
语句1;
语句2;
...
}
else if(条件2)
{
语句1;
语句2;
...
}
else
{
语句1;
语句2;
...
}

例子:判断出/etc/passwd文件中的哪些用户属于系统用户,哪些用户属于普通用户
在这里插入图片描述
在这里插入图片描述

好了,再来看一个"if…else if…else"这样的例子,其他它们都差不多,示例如下:
在这里插入图片描述
7.2 for循环和while循环

#for循环语法格式1
for(初始化; 布尔表达式; 更新) {
//代码语句
}
 
#for循环语法格式2
for(变量 in 数组) {
//代码语句
}
 
#while循环语法
while( 布尔表达式 ) {
//代码语句
}
 
#do...while循环语法
do {
//代码语句
}while(条件)

先来开开胃,帮你回忆什么是for循环和while循环
必须使用BEGIN模式才可以。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
正如上图所示,无论是否满足while中的条件,都会先执行一遍do对应的代码。

那么,说到循环,就不能不说说与循环有关的跳出语句。

没错,与其他编程语言中一样,在awk中,同样可以使用break与continue跳出循环。

continue的作用:跳出"当前"循环

break的作用:跳出"整个"循环

首先看一下continue跳出循环
在这里插入图片描述
由于在for循环中添加了条件判断,所以当 i 的值为 3 时,跳过了"当前本次"循环,没有执行当前本次循环需要执行的动作,所以上例中,数字"3"并没有被打印出来

当然,如果你想"结束"的更加"彻底",可以使用break结束循环,示例如下。
在这里插入图片描述
如上图所示,break结束的更加彻底,当使用break时,整个循环都将被结束,循环中的动作将不会再被执行。

如果你经常编写过shell脚本,你可能会问,awk中有类似exit的语句吗?必须有啊,在shell中,exit命令表示退出当前脚本,在awk中,它的含义也是类似的,它表示不再执行awk命令,相当于退出了当前的awk命令,示例如下。
在这里插入图片描述
如上图所示,上图中第一条命令中,执行了多个动作(多条语句),上图中的第二条命令中,也执行了多个动作,但是当在awk中执行了exit语句以后,之后的所有动作都不会再被执行,相当于退出了整个awk命令。

其实,这样描述exit的作用并不准确,因为,当在awk中使用了END模式时,exit的作用并不是退出整个awk命令,而是直接执行END模式中的动作,示例如下。
在这里插入图片描述
如上图所示,当awk中使用了END模式时,如果执行了exit语句,那么exit语句之后的所有动作都将不会再被执行,END模式中的动作除外。
换句话说就是,当执行了exit语句后,如果使用了END模式,将直接执行END模式中的动作,其他动作将不会被执行,如果没有使用END模式,当执行了exit语句后,将直接退出整个awk命令

在awk中,除了能够使用"exit命令"结束"整个awk",还能够使用"next命令"结束"当前行",什么意思呢?我们慢慢聊。

在前文中,我们提到过,awk是逐行对文本进行处理的,也就是说,awk会处理完当前行,再继续处理下一行,那么,当awk需要处理某一行文本的时候,我们能不能够告诉awk :“不用处理这一行了,直接从下一行开始处理就行了”。

没错,使用next命令即可让awk直接从下一行开始处理,换句话说就是,next命令可以促使awk不对当前行执行对应的动作,而是直接处理下一行,示例如下
在这里插入图片描述其实,next与continue有些类似,只是,continue是针对"循环"而言的,continue的作用是结束"本次循环",而next是针对"逐行处理"而言的,next的作用是结束"对当前行的处理",从而直接处理"下一行",其实,awk的"逐行处理"也可以理解成为一种"循环",因为awk一直在"循环"处理着"每一行",不是吗?

awk的常用的流程控制语句与循环语句都已经总结完毕了

8.awk数组

如果你有过任何一种编程语言的使用经验,那么你一定知道,我们可以通过数组的下标(或者称索引),引用数组中的元素,其他语言中,数组的下标通常由0开始,也就是说,如果想要引用数组中的第1个元素,则需要引用对应的下标"[0]",awk中的数组也是通过引用下标的方法,获取数组中的元素的,但是在awk中,数组元素的下标默认从1开始,但是为了兼容你的使用习惯,我们也可以从0开始设置下标,此处不用纠结,到后面自然会明白,我们先来看一个最简单的示例。
在这里插入图片描述
如上图所示,为了方便示例,上例中使用了BEGIN模式,在BEGIN模式中,存在一个名为"葫芦娃"(拼音)的数组,我们在这个数组中放置了3个元素,第1个元素为"大娃",第2个元素为"二娃",第3个元素为"三娃",如果我们想要引用数组中第三个元素的值,只要引用下标为1的元素即可,正如上图所示,我们使用下标"[2]",获得了huluwa这个数组中第三个元素的值,即"三娃"。当然,如果你想要看到更多的"葫芦娃",可以在数组里面放置更多的元素。

我们知道,在动画中,六娃的超能力是"隐身",所以六娃也叫"隐身娃",那么,我们就把上述数组中的第5个元素的值设置为"空字符串"吧,用空字符串表示六娃已经"隐身"了,示例如下。

在这里插入图片描述
如上图所示,上例数组中的第5个元素的值被设置为了"空字符串",当我们打印数组中的第5个元素的值时,打印出的值就是"空"(注:“空格"不为"空”)。

为什么要举这个例子呢?之所以举这个例子,是因为在awk中,元素的值可以设置为"空",在awk中,将元素的值设置为"空字符串"是合法的。

既然在awk中,元素的值可以为"空",那么我们就不能再根据元素的值是否为"空"去判断元素是否存在了,所以,在awk中,如果你使用如下方法判断数组中的元素是否存在,是不合理的,如下图所示。
在这里插入图片描述
正如上图所示,第6个元素明明已经存在,但是通过上述方法判断元素是否存在时,仍然显示对应的元素不存在。

其实,使用上述方法判断元素是否存在之所以不合理,除了上述原因,还有另外一个原因,就是当一个元素不存在于数组时,如果我们直接引用这个不存在的元素,awk会自动创建这个元素,并且默认为这个元素赋值为"空字符串",数组中并没有第7个元素,但是当我们输出第7个元素时,输出了"空",所以,出于此原因,在awk中使用之前的方法判断元素是否为空也是不合理的,因为当我们引用一个不存在于数组中的元素时,这个元素其实已经被赋值为"空字符串"了,示例如下。
在这里插入图片描述
那么,在awk中,应该怎样判断元素是否存在呢?我们可以使用如下语法。
在这里插入图片描述如上图所示,我们可以使用语法 “if(下标 in 数组名)” ,从而判断数组中是否存在对应的元素。

当然,我们还可以使用 “!” 对条件进行取反,如下图所示。
在这里插入图片描述
其实,awk中的数组本来就是"关联数组",之所以先用以数字作为下标的数组举例,是为了让读者能够更好的过度,不过,以数字作为数组下标的数组在某些场景中有一定的优势,但是它本质上也是关联数组,awk默认会把"数字"下标转换为"字符串",所以,本质上它还是一个使用字符串作为下标的关联数组。

在awk中,数组的下标不仅可以为"数字",还可以为"任意字符串",如果你使用过shell中的数组,你可以把awk的数组比作bash中的"关联数组",示例如下
在这里插入图片描述
其实,awk中的数组本来就是"关联数组",之所以先用以数字作为下标的数组举例,是为了让读者能够更好的过度,不过,以数字作为数组下标的数组在某些场景中有一定的优势,但是它本质上也是关联数组,awk默认会把"数字"下标转换为"字符串",所以,本质上它还是一个使用字符串作为下标的关联数组。

使用delete可以删除数组中的元素,如下所示
在这里插入图片描述
也可以使用delete删除整个数组,如下所示
在这里插入图片描述

到目前为止,我们已经介绍了怎样为数组中的元素赋值、怎样输出数组中的某个元素、以及怎样删除数组中的元素,那么现在,我们来聊聊在awk中怎样输出数组中的所有元素,在awk中,如果想要输出数组中的所有元素,则需要借助for循环语句,还记得在前文中介绍for循环时,有两种for循环语法吗?我们来回顾一下。

#for循环语法格式1
for(初始化; 布尔表达式; 更新) {
//代码语句
}
 
#for循环语法格式2
for(变量 in 数组) {
//代码语句
}

这两种for循环语法都能够遍历输出数组中的元素,不过第一种for循环语法只能输出以数字作为下标的数组,示例如下
在这里插入图片描述你一定看出来了,我们利用了for循环中的变量"i"与数组中的下标都是"数字"的这一特性,按照顺序输出了数组中的元素值。

那么,当数组中的元素的下标为"无规律的字符串"时,我们该怎么办呢?这时可以使用for循环的第二种语法,示例如下。
在这里插入图片描述
注意,在这种语法中,for循环中的变量"i"表示的是元素的下标,而并非表示元素的值,所以,如果想要输出元素的值,则需要使用"print 数组名[变量]"
细心如你,一定发现了一个小问题,当数组中的下标为"字符串"时,元素值输出的顺序与元素在数组中的顺序不同,这是因为awk中的数组本质上是关联数组,所以默认打印出的元素是无序的。

这就是以数字作为下标的优势,因为第一种for循环语法中的变量"i"为数字,由于for循环的原因,"i"是按照顺序递增的,当"i"的值与下标的值相同时,我们即可按照下标的顺序,输出对应元素的值,换句话说就是,我们是通过下标的顺序,输出对应元素值的顺序,也就是键值定位。但是,即使数组元素的下标为数字,如果使用第二种for循环语法,也不能够按照顺序输出,示例如下

在这里插入图片描述

上例又印证我们之前所说的,awk中的数组本质上就是关联数组。

我想,经过上述对比,你应该已经明白了。

前文中,我们都是手动的为数组中的元素赋值,那么我们能不能将指定的文本分割,然后将分割后的字段自动赋值到数组的元素中呢?答案是必须的,但是如果我们想要实现这样的效果,需要借助于split函数,而我们还没有介绍过函数,所以此处就先跳过了,不过需要提前说明的是,通过split函数生成的数组的下标默认是从1开始的,这就是为什么之前说,awk中数组的下标默认是从1开始的了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值