GAWK命令内建变量的使用
1 GAWK程序介绍
gawk
程序是awk
程序的GNU版本,它能提供一个类编程环境来修改和重新组织文件中的数据,以生成满足特定格式的易于阅读的报告。在现在的centos6和centos7中使用的awk
程序实际通过软链接指向了gawk
程序。
[root@Centos7T ~]#ll `which awk`
lrwxrwxrwx. 1 root root 4 Jul 14 12:08 /usr/bin/awk -> gawk
我们可以利用gawk
的编程能力完成以下功能:
* 定义变量来保存数据;
* 使用算术和字符串操作符来处理数据;
* 使用结构化编程概念(比如if-then语句和循环)来为数据处理增加处理逻辑;
* 通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告。
本文单就gawk
程序的内建变量进行简单介绍,而gawk
的內建变量又分为两类:
1. 字段和记录分隔符变量
2. 数据变量
2 字段和记录分隔符变量
顾名思义,字段和记录分隔符变量被用来指定分隔符,以分隔需要处理的字段和记录,从而可以方便的提取出我们所需要的数据。gawk
程序使用的分隔符变量如下:
FIELDWIDTHS 由空格分隔的一列数字,定义了每个数据字段确切宽度
FS 输入字段分隔符
RS 输入记录分隔符
OFS 输出字段分隔符,默认一个空格
ORS 输出记录分隔符
变量FS
指定了一条记录内部各个数据字段的分隔符,这样我们就可以提取指定的字段。而在gawk
程序处理输出的各个字段同样可以使用分隔符隔开,已达到格式化输出的目的。针对输出结果的分隔符,我们可以使用变量OFS
指定。变量FS
和OFS
的默认值都是空格。
[root@Centos7T gawk]#cat t1
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
[root@Centos7T gawk]#gawk 'BEGIN{FS=","} {print $1,$3,$5}' t1
data11 data13 data15
data21 data23 data25
data31 data33 data35
[root@Centos7T gawk]#gawk 'BEGIN{FS=",";OFS="--"} {print $1,$3,$5}' t1
data11--data13--data15
data21--data23--data25
data31--data33--data35
原始数据都是使用,
分隔,在第一次使用gawk
程序梳理t1文件的数据时,我们指定FS=","
,然后打印每条记录的第1、3、5个字段的数据,而输出分隔符未指定,使用默认的空格将三个数据字段分隔开。在第二次使用
gawk
程序处理t1文件的数据时,我们指定FS=","
和OFS="--"
,然后打印每条记录的第1、3、5个字段的数据,而输出的三个字段将会被--
分隔开。
由于gawk
程序处理数据是按照一条记录一条记录依次进行的,为了让gawk
程序能够按照我们的期望识别各条数据记录,我们需要通过变量RS
指定的待处理数据的记录分隔符。多条记录经过gawk
程序处理输出的结果同样需要使用分隔符隔开,我们可以使用变量ORS
指定。变量RS
和ORS
的默认值都是换行符\n
。
[root@Centos7T gawk]#cat t1-1
data11,data12,data13;data21,data22,data23;data31,data32,data33
[root@Centos7T gawk]#gawk 'BEGIN{FS=","} {print $1,$3}' t1-1
data11 data13;data21
[root@Centos7T gawk]#gawk 'BEGIN{FS=",";RS=";"} {print $1,$3}' t1-1
data11 data13
data21 data23
data31 data33
上述代码分别指定了RS
使用默认值和RS=";"
,两者输出结果对比很明显存在差异性。
变量FIELDWIDTHS
设定了一条记录内部各个数据字段的宽度,以此来分隔并识别各个数据字段。变量FIELDWIDTHS
规定了将例句分隔成几段,每个字段的宽度,例如FIELDWIDTHS="5 5 2 4"
。
[root@Centos7T gawk]#cat t1-2
6546845686
6354654687
6574864561
[root@Centos7T gawk]#gawk 'BEGIN{FIELDWIDTHS="3 2 4 1"} {print $1,$2,$3,$4}' t1-2
654 68 4568 6
635 46 5468 7
657 48 6456 1
变量FIELDWIDTHS="3 2 4 1"
将每条记录分隔成4个字段,每个字段的宽度分别为3、2、4、1。通过该变量,我们很容易的获取固定列宽度的数据。
3 数据变量
gawk
使用的数据变量除了前文我们使用到的诸如$1
、$2
、$3
、$4
这样的用于记录中各个提取数据字段的变量,类似于shell脚本的命令行参数(参考我的其他文章:Bash Shell命令行参数的使用)。但不同之处在于$0
在命令行参数中表示脚本程序名称,而在gawk程序中,$0
存储的是当前gawk程序正在处理的整条记录。
[root@Centos7T gawk]#cat t1-3
How are you
[root@Centos7T gawk]#gawk '{print "$1:",$1,"\n$2:",$2,"\n$3:",$3,"\n$0:",$0}' t1-3
$1: How
$2: are
$3: you
$0: How are you
另外,gawk
还有如下常用的内部变量,如下所示:
ARGC 当前命令行参数个数
ARGIND 当前文件在ARGV中的位置
ARGV 包含命令行参数的数组,
ENVIRON 当前shell环境变量及其值组成的关联数组
NF 数据文件中的字段总数
NR 已处理的输入记录数
FNR 当前数据文件中的数据行数
RLENGTH 由match函数所匹配的子字符串的长度
RSTART 由match函数所匹配的子字符串的起始位置
变量ARGC
、ARGIND
、ARGV
用于获取gawk
的命令行参数,其中变量ARGC
可以获取gawk
包括程序名本身、需要处理的文件在内的命令行参数的总数;但要注意,程序脚本并不被当做命令行参数。变量ARGV
是用于存储命令行参数的数组,ARGV
数组从索引0开始,代表的是命令,第一个数组值是gawk命令后的第一个命令行参数。ARGIND
用于获取当前正在被gawk
程序处理的数据文件名称。如果文件包含路径则一并视为文件名。
[root@Centos7T gawk]#cat file1
This is the first file first line
This is the first file second line
[root@Centos7T gawk]#cat file2
This is the second file first line
This is the second file second line
[root@Centos7T gawk]#gawk '{print ARGC,ARGIND,ARGV[ARGC-1],ARGV[1]}' file1 file2
3 1 file2 file1
3 1 file2 file1
3 2 file2 file1
3 2 file2 file1
在本例中,使用ARGV[ARGC-1]
获取最后一个gawk
程序的命令行参数。
变量ENVIRON
利用关联数组来获取当前shell的环境变量。关联数组ENVIRON
的索引应该为shell环境变量的变量名称。例如我们可以利用ENVIRON["HOSTNAME"]
来获取当前Shell的hostname
。注意,环境变量名应该使用双引号。
[root@Centos7T gawk]#cat t1-3
How are you
[root@Centos7T gawk]#gawk '{print ENVIRON["HOSTNAME"]}' t1-3
Centos7.magedu.com
[root@Centos7T gawk]#gawk '{print ENVIRON["PATH"]}' t1-3
/app/httpd22/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@Centos7T gawk]#gawk '{print ENVIRON["PWD"]}' t1-3
/app/gawk
变量FNR
、NF
和NR
用于在gawk程序中跟踪数据字段和记录。变量FNR
含有当前数据文件中已处理过的记录数;变量NR
则含有已处理过的记录总数。二者不同之在于,变量FNR
针对当前正在处理的文件。当一个数据文件处理完毕,开始处理下一个文件,例如上面例子中,file1处理完毕开始处理file2,此时变量FNR
会被重置为1,而变量NR
还会继续计数,不会被重置。而变量NF
则含有当前gawk正在处理的数据的字段总数。
[root@Centos7T gawk]#gawk '{print NR,FNR,"the last word is:",$NF}' file1 file2
1 1 the last word is: line
2 2 the last word is: line
3 1 the last word is: line
4 2 the last word is: line
由于变量NF
则含有当前gawk
正在处理的数据的字段总数,那么可以利用引用数据字段的方式,利用$NF
引用当前记录的最后一个字段。
变量RLENGTH
和RSTART
可以配合match
函数对匹配到的字符串记录其长度和位置。匹配可以使用指定的字符串、通配符、正则表达式。 match
函数的基本格式为match(s,r[,a])
,表示在字符串s
中匹配r
,r
可以为字符串或者正则表达式,并将匹配结果存储在数组a
中。
[root@Centos7T gawk]#gawk 'BEGIN{match("nf38472we30f","we",str);print RSTART,RLENGTH,str[0]}'
8 2 we
[root@Centos7T gawk]#gawk 'BEGIN{match("secure2017-09-17_logfile",/([0-9]+-)+[0-9]+/,date);print RSTART,RLENGTH,date[0]}'
7 10 2017-09-17
在第二个例子中可以很容易的提取其中的日期字符串。至此,关于gawk
常用的命令接介绍到这里。