一、awk内置变量
名称
含义 ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk浏览的文件名 FNR 浏览文件的记录数 FS 设置输入域分隔符,等价于命令行-F选项 NF 浏览记录的域的个数 NR 已读的记录个数 OFS 输出域分隔符 ORS 输出记录分隔符 RS 控制记录分隔符
1.1ARGV和ARGC举例:
ARGV表示awk命令的参数,需要注意的是awk命令本身也是一个参数,在下面的命令中,参数有四个,分别是:awk、1、2、3,因此ARGC=4。
[root@randow_wz mnt]# awk 'BEGIN{for(i=0; i<ARGC; i++) print ARGV[i]}' 1 2 3
awk
1
2
3
1.2ENVIRON举例
ENVIRON是一个数组,下标为对应环境变量的值,元素为对应的环境变量。下例中,使用OFS指定输出域的分隔符为冒号,方便查看。
[root@random_wz mnt]# awk 'BEGIN{OFS=":"; for(x in ENVIRON) print x,ENVIRON[x]}'
AWKPATH:.:/usr/share/awk
HOME:/root
PWD:/mnt
1.3 FNR和NR举例
NR表示已读的记录数,FNR表示浏览文件的记录数,小于等于NR(比如当读取第二个文件时,FNR是从1开始重新计数,而NR不会)。NR==FNR:用于在读取两个或两个以上的文件时,判断是不是在读取第一个文件。
对于NR,读取不同文件,NR是一直++的,但是FNR当读取新文件时,值是从1开始的。
[root@random_wz mnt]# cat 1.txt
aaa
bbb
ccc
[root@random_wz mnt]# cat 2.txt
ddd
eee
fff
[root@random_wz mnt]# awk '{OFS=":";print FNR,$0}' 1.txt 2.txt
1:aaa
2:bbb
3:ccc
1:ddd
2:eee
3:fff
[root@random_wz mnt]# awk '{OFS=":";print NR,$0}' 1.txt 2.txt
1:aaa
2:bbb
3:ccc
4:ddd
5:eee
6:fff
1.4 FILENAME举例
FILENAME表示输入的文件名称
[root@random_wz mnt]# awk 'END{print FILENAME}' 1.txt
1.txt
1.5 RS和ORS举例
ORS表示输出记录分隔符,比如分隔符默认为换行符,你可以指定在输出的时候用其他分割符表示,RS表示控制记录分隔符,即你可以指定分隔符。
默认以换行符分割域,使用ORS指定输出时将换行符用*替换
[root@random_wz mnt]# cat 1.txt
aaa
bbb
ccc
[root@random_wz mnt]# awk 'BEGIN{ORS="*"}{print $0}' 1.txt
aaa*bbb*ccc*
通过RS指定每条记录的分割符为|
[root@random_wz mnt]# cat 1.txt
aaa|bbb|ccc
[root@random_wz mnt]# awk 'BEGIN{RS="|"}{print $0}' 1.txt
aaa
bbb
ccc
1.6 NF和NR举例
NF表示浏览记录域的个数,NR为已读的记录个数。
$NF表示最后一个域
[root@random_wz mnt]# cat 1.txt
aaa
bbb
ccc
[root@random_wz mnt]# awk 'BEGIN{OFS=":"}{print NR,$NF}' 1.txt
1:aaa
2:bbb
3:ccc
二、流程控制
2.1 条件判断语句(if)
格式为:if(表达式) 语句一 else 语句二
当然你也可以将多个语句用{}括起来,Unix awk命令允许嵌套,如下:
if(表达式) {语句一} else if(表达式二) 语句二 else {语句三}
举两个例子,第一个不嵌套:
[root@random_wz mnt]# awk 'BEGIN{test=20; if(test>10) print "very good"; else print "bad"}'
very good
注意上面的例子中,如果命令写在一行,则需要注意加分号,其中if(表达式) 语句一为一个整体,在语句一后面加分号,else语句二为一个整体,如果else语句在最后,则可以不加分号,在下面的例子中展示了分行时可以省略分号的例子。
[root@random_wz mnt]# awk 'BEGIN{
> test=20
> if(test>10)
> print "very good"
> else
> print "bad"
> }'
very good
第二个例子,使用{}将语句括起来
[root@random_wz mnt]# awk 'BEGIN{
> test=70
> if(test=70)
> {
> print "***********************************************"
> print " Wishing China 70 Years Old Happy birthday "
> print "***********************************************"
> }
> else if(test>100)
{
> print "Good"
> }
> else
> {
> print "Bad"
> }
> }'
***********************************************
Wishing China 70 Years Old Happy birthday
***********************************************
如果写在一行,注意要加分号。
2.2 while语句
格式:while(表达式) {语句}
直接上个例子
[root@random_wz mnt]# awk 'BEGIN{
> Sum=0
> i=0
> while(i<5)
> {
> print Sum,"+",i,"=",Sum+i
> Sum+=i
> i++
> }
> }'
0 + 0 = 0
0 + 1 = 1
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
我在学习while的时候发现一个问题,当awk语句后面没有文件的时候,只有BEGIN语句可以执行,来一个例子说明:
[root@random_wz mnt]# awk 'BEGIN{
> Sum=0
> i=0
> while(i<5)
> {
> print Sum,"+",i,"=",Sum+i
> Sum+=i
> i++
> }
> }
> END{
> print "Sum=",Sum
> }'
0 + 0 = 0
0 + 1 = 1
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
执行后鼠标会一致卡在这
鼠标一直卡着的原因如下:
- BEGIN{},为行前处理,也就是在行之前操作,通常为初始化操作,是可选项,当awk语句只有BEGIN时,不需要再后面接文件。
- {},awk语法的第二部分为行处理,用来处理读入的行,因此当awk语句中有行处理部分的话必须要再后面接需要进行处理的文件名称。
- END{},为行后处理,awk命令将所有的行处理完成后执行的操作,一般输出处理结果,因此当awk语句中包含END语句的时候,后面必须要接需要处理的文件名称,这也是为什么上面的例子会一直卡住的原因。
2.3 do-while循环
格式:do {语句} while(条件)
格式和C语言中的do-while是一致的,举例如下:
[root@random_wz mnt]# awk 'BEGIN{
> Sum=0
> i=0
> do
> {
> print Sum,"+",i,"=",Sum+i
> Sum+=i
> i++
> }
> while(i<10)
> }'
0 + 0 = 0
0 + 1 = 1
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
10 + 5 = 15
15 + 6 = 21
21 + 7 = 28
28 + 8 = 36
36 + 9 = 45
2.4 下面介绍流程控制语句中会用到的一些语句
语句 | 含义 |
---|---|
break | 当 break 语句用于 while 或 for 语句时,导致退出程序循环。 |
continue | 当 continue 语句用于 while 或 for 语句时,使程序循环移动到下一个迭代。 |
next | 能够导致读入下一个输入行,并返回到脚本的顶部。这可以避免对当前输入行执行其他的操作过程。 |
exit | 语句使主输入循环退出并将控制转移到END,如果END存在的话。如果没有定义END规则,或在END中应用exit语句,则终止脚本的执行。 |
这里举个例子说一下next的用法:
[root@viper-unity-va-ut-ff2103-24 mnt]# cat 1.txt
No Item_Name Price Quantity
1 Mangoes $3.45 5
2 Apples $2.45 25
3 Pineapples $4.45 55
4 Tomatoes $3.45 25
5 Onions $1.45 15
6 Bananas $3.45 30
[root@viper-unity-va-ut-ff2103-24 mnt]# awk '$4 <= 20 { printf "%s\t%s\n", $0,"*" ; } $4 > 20 { print $0 ;} ' 1.txt
No Item_Name Price Quantity
1 Mangoes $3.45 5 *
2 Apples $2.45 25
3 Pineapples $4.45 55
4 Tomatoes $3.45 25
5 Onions $1.45 15 *
6 Bananas $3.45 30
上面的例子是给价格不超过20的水果条目后面加一个星号,每次第一个判断完成后,还会进行第二次判断,会比较良妃时间,因此加入next语句,在第一次判断完后,满足条件,会跳过第二个判断,从而开始新的迭代。
[root@viper-unity-va-ut-ff2103-24 mnt]# awk '$4 <= 20 { printf "%s\t%s\n", $0,"*" ; next; } $4 > 20 { print $0 ;} ' 1.txt
No Item_Name Price Quantity
1 Mangoes $3.45 5 *
2 Apples $2.45 25
3 Pineapples $4.45 55
4 Tomatoes $3.45 25
5 Onions $1.45 15 *
6 Bananas $3.45 30
三、printf语句
最后简单说一下printf语句在awk命令中的使用,前面的例子已经出现过,在awk语句中printf的用法和在C语言中是一致的。
这里通过表格列出来一些常用的修饰符。
修饰符 | 含义 |
---|---|
- | 左对齐修饰符 |
# | 显示8进制整数前面加个0 显示16进制整数前面加0x |
+ | 整数前面加正负号 |
0 | 用0填充所显示的值 |