三、awk语言特性
3.1 awk代码特性
通常情况下,awk会针对每一个输入执行一段代码块。但是有些时候,我们需要在awk开始处理输入之前执行一些数据的初始化。awk定义了BEGIN和END代码块,BEGIN代码块是进行awk部分参数的初始化操作,END代码块是在所有的输入都处理完后,然后awk运行代码。BEGIN和END代码块均为可选项。
3.1.1 BEGIN代码块
在上一次的学习里,我们利用-F ":"重新定义分隔符号为冒号(:),下面展示使用BEGIN代码块实现重定义分隔符号为冒号的功能。
- 使用文件来编写awk代码
首先,在terminal创建fs.awk文件,文件内容如下:
BEGIN {
FS=":"
}
{
print $1 $3
}
awk中定义FS变量为字段分隔符,这里将冒号赋值给了FS,awk在初始化操作过程中就会将默认分隔符改变为冒号。
之后在terminal调用fs.awk文件,就可以实现分隔符号为冒号时输出1.rpt文件的第一列与第三列的功能。
head -n10 1.rpt | awk -f fs.awk
上述的操作是使用一个文件来编写awk脚本,然后使用-f参数将fs.awk文件传递到命令中。
- 使用单行语句编写awk代码
还可以将fs.awk脚本内容写到一行里(这种方法感觉对于执行复杂的内容 书写起来相对繁琐,不太推荐):
head -n10 1.rpt | awk 'BEGIN {FS=":"} {print $1 $3}'
3.1.2 END代码块
END代码块中,awk可以执行一些类似于统计数据,打印输出之类的操作。
首先,在terminal创建search.awk文件,文件内容如下:
/VIOLATED/ {++adder} #固定匹配字符串‘VIOLATED’,如果匹配上了,就执行{}之间的内容,即++adder(不懂啥意思,还没学呢)
END { #end代码块执行awk脚本的扫尾工作,这段代码将统计的1.rpt中VIOLATED字符出现的次数打印出来。
print "'VIOLATED' appears " adder " times."
}
之后在terminal调用:
awk -f search.awk 1.rpt
当然,还可以在search.awk文件利用BEGIN代码块写一些提示信息,这样便于运行程序的人能够看懂程序:
BEGIN {
print "How many times 'VIOLATED' appears?"
}
/VIOLATED/ {++adder}
END {
print "'VIOLATED' appears " adder " times."
}
以上写在BEGIN代码块和END代码块的代码分别在初始化和所有输入数据处理完成后执行一次(仅一次)。
3.1.3 模式匹配
我们可以使用模式匹配来使awk仅仅对部分的数据进行操作,而其他匹配不上的数据,awk将不作任何处理。在上述例子,awk会去匹配数据中的‘VIOLATED’正则表达式,匹配上才执行++adder。因此可以知道,awk匹配模式的语法如下:
/正则表达式/ {匹配后的操作}
- 模式匹配
awk '/^$/ {print "This is an empty line."}' 1.rpt #查看1.rpt文件中的空行数目。正则表达式^$匹配文件中的空行,当匹配上时,执行awk的print语句
awk '/VIOLATED/ {print $1}' 1.rpt #使用正则表达式VIOLATED检索1.rpt文件中的每一行,当匹配上VIOLATED时,使用print语句打印出对应行的第一个字段
- 多项模式匹配
我们还可以在一个awk脚本中写出多个模式匹配代码,对匹配上的不同正则表达式的数据采用不同的处理:
/VIOLATED/ {++violated} #支持的第一个匹配
/MEET/ {++meet} #支持的第二个匹配
END {
print "'VIOLATED' appears " violated " times."
print "'MEET' appears " meet " times."
}
3.2 数组与变量
3.2.1 变量
awk中有两种变量:用户自定义变量和内建变量。
在上文中,使用adder/violated/meet变量来统计VIOLATED/MEET字符串出现的次数,此处的adder/violated/meet就是用户自定义变量(书上对应描述VIOLATED/MEET为用户自定义变量,感觉有点问题);同时在上文我们重定义FS为冒号(:),此处FS即为内建变量。
awk的变量使用不需要先声明,而是在第一次使用该变量的时候自动建立变量(所以前面可以直接使用adder/violated/meet)。awk的变量在建立时的初始值都是空字符串,但是当需要数值时,它会被视为0。也就是说,awk会自动将字符串转换为数值进行计算。
awk变量必须以ASCII字母或下划线开始,然后选择性的街上字母、下划线及数字。如果用正则表达式来匹配变量名的话,awk的变量名必须匹配[A-Za-z_][A-Za-z_0-9]*。在长度上,awk的变量名没有限制。
awk变量名称区分大小写,如you、You及YOU是三个完全不同的名称。因此,可以按照以下建议:局部变量小写,全局变量首字母大写,内建变量全部大写。
以下为awk常用的内建变量:
变量 | 说明 |
FILENAME | 当前输入文件的名称 |
FNR | 当前输入文件的记录 |
FS | 字段分隔符(支持正则表达式),默认为空格 |
NF | 当前记录的字段数 |
NR | 在工作(job)中的记录数 |
OFS | 输出字段分隔字符 |
ORS | 输出记录分隔字符(默认为“\n”) |
RS | 输入记录分隔字符 |
3.2.2 数组
awk中的数组命名遵循了与变量命名相同的惯例。。。。这部分内容还不太理解
3.2.3 环境变量
awk支持直接对环境变量的访问,通过ENVIRON数组。
3.3 算数运算和运算符
在awk中可以直接进行算术运算。
awk 'BEGIN {print "3+2=" 3+2}' #执行结果:3+2=5
awk 'BEGIN {print "2^10=" 2^10}' #2^10=1024
awk 'BEGIN {print "(3+2)*7" (3+2)*7}' #(3+2)*7=35
下面表格为awk支持的运算符:
运算符 | 描述 |
= =+ -= *= /= %= ^= **= | 赋值 |
?: | C条件表达式 |
|| | 逻辑或 |
&& | 逻辑与 |
~ ~! | 匹配正则表达式和不匹配正则表达式 |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加减 |
* / % | 乘,除与求余 |
+-! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 增加或减少,作为前缀和后缀 |
$ | 字段引用 |
in | 数组成员 |
关于以上表格的一些解释:
(1)条件表达式:条件表达式是利用某条件判断的结果来决定该返回哪个表达式。例如,为了实现max(x,y),可以写成 x>y?x:y。这种表达式的含义是判断x是否大于y,如果是则返回x,如果不是则返回y。
(2)*=运算符。例如:x*=y,效果相当于x=x×y。
(3)++运算符。例如:x++,相当于x=x+1。
我们可以利用其中一些运算符来写一个判断年份是闰年还是平年:如果年份能被4整除但是不能被100整除,或者年份能被400整除,这两种情况的年份为闰年;其他则为平年。
现year.text中的内容如下:
1987
2008
3000
2000
2012
1200
1300
判断平闰年的leap.awk脚本内容:
BEGIN {
print "Pick leap years:"
}
{
year = $1 #将第一列内容赋值给year;同时awk不要求先声明变量,所以这里可以直接使用
if ((year %4 == 0 && year %100 != 0) || year %400 == 0)
print year " is a leap year."
else
print year " is not a leap year."
}
使用awk调用leap.awk脚本,附执行结果:
awk -f leap.awk year.text
#执行结果
Pick leap years:
1987 is not a leap year.
2008 is a leap year.
3000 is not a leap year.
2000 is a leap year.
2012 is a leap year.
1200 is a leap year.
1300 is not a leap year.
3.4 判断与循环
awk中的条件语句主要有if/else语句,循环有for和while。(主要是书写格式)
3.4.1 if语句
{
if (expression) {
statement;statement;...
}
}
3.4.2 if/else语句
{
if (expression) {
statement;statement;...
}
else {
statement;statement;...
}
}
3.4.3 if/else else if语句
{
if (expression) {
statement;statement;...
}
else if (expression) {
statement;statement;...
}
else if (expression) {
statement;statement;...
}
else {
statement;statement;...
}
}
3.4.4 while循环
While (condition) {
action
}
#举例,让某个循环执行4次
i = 4
while (i >=1) {
print $i
i--
}
3.4.5 do/while循环
awk的do...while循环,是在代码块结尾处对条件求值,而不像标准while循环那样在开始处求值。所以“do...while”循环永远都至少执行一次。
{
count=1
do { #这一行将至少被执行一次
print "haaaaaaa"
} while (count !=1) #此处的while判断如果不被满足,则退出循环
}
3.4.6 for循环
for (initial assignment;comparison;increment) {
code block
}
下面为一个例子及效果,x初始值为1,然后执行判断是否x<=4,判断为真则执行循环体,然后x++,对于x++的结果再判断是否x<=4。。。。。
for (x = 1 ;x <=4 ; x++) {
print "iteration",x
}
##打印结果如下:
iteration 1
iteration 2
iteration 3
iteration 4
3.4.7 break和continue
x=1
while (1) {
print "haa" ,x
if (x == 10) {
break
}
x++
}
暂时够用 不学了