awk NR详解!awk 的内置变量 NF、NR、FNR、FS、OFS、RS、ORS

发布时间 2023-07-19 20:59:31作者: Harda

NF 字段个数,(读取的列数)
NR 记录数(行号),从1开始,新的文件延续上面的计数,新文件不从1开始
FNR 读取文件的记录数(行号),从1开始,新的文件重新从1开始计数
FS 输入字段分隔符,默认是空格
OFS 输出字段分隔符 默认也是空格
RS 输入行分隔符,默认为换行符
ORS 输出行分隔符,默认为换行符

NF
读取记录的字段数(列数),例如:

[root@localhost test]# awk '{print "字段数:" NF}' test
字段数:4
字段数:4
字段数:3
字段数:4
字段数:4
[root@localhost test]# cat test
a aa aaa 1
b bb bbb 2
c cc ccc
d dd ddd 4
e ee eee 5

如上,awk在读取文件时,按行读取,每一行的字段数(列数),赋值给内置变量NF,打印出来的就是每行的字段总数,有以下简单示例:

[root@localhost test]# awk '{print $NF}' test
1
2
ccc
4
5
t@localhost test]# cat test
a aa aaa 1
b bb bbb 2
c cc ccc
d dd ddd 4
e ee eee 5

我们有需求,只需要最后一列的数据,由于每一行的列数不一,最后一列无法指定固定的列数,可以使用NF来表示列数 $NF 表示打印出等于总列数的那一列的数据,显而易见就是打印最后一列的数据

NR
读取文件的行数(在某些应用场景中可以当作行号来使用)

[root@localhost test]# awk '{print "行号为:" NR}' test
行号为:1
行号为:2
行号为:3
行号为:4
行号为:5
[root@localhost test]# cat test
a aa aaa 1
b bb bbb 2
c cc ccc
d dd ddd 4
e ee eee 5

如上,打印出读取文件的行数,因为是按行读取,在应用场景中,行数可以等同于行号,用来输出对应行的行号,NR 还可以用作判断输出,如下简单例子:

[root@localhost test]# awk '{if(NR>2)print "行号为:" NR }' test
行号为:3
行号为:4
行号为:5

判断当读取的行数(行号)大于2时,输出对应的内容。

FNR
也是读取文件的行数,但是和NR 不同的是当读取的文件有两个或两个以上时,NR 读取完一个文件,行数继续增加 而FNR 重新从1开始记录

[root@localhost test]# awk '{print "NR:" NR "FNR:" FNR}' test test2 test3
NR:1FNR:1
NR:2FNR:2
NR:3FNR:3
NR:4FNR:4
NR:5FNR:5
NR:6FNR:1
NR:7FNR:2
NR:8FNR:3
NR:9FNR:1
[root@localhost test]# cat test
a aa aaa 1
b bb bbb 2
c cc ccc
d dd ddd 4
e ee eee 5
[root@localhost test]# cat test2
! !! !!! 1
@ @@ @@@ 2
# ## ### 3
[root@localhost test]# cat test3
bbbbb nnnnn mmmm

如上,总共有三个文件,读取三个文件NR 从一开始一直增加,FNR 每读取到一个新的文件,行数重新从一开始增加,有一个有趣的应用,比较两个文件A,B是否一致,以A作为参考,不一致的输出行号

[root@localhost test]# awk '{if(NR==FNR){arry[NR]=$0}else{if(arry[FNR]!=$0){print FNR}}}' test test1
3
[root@localhost test]# cat test
a aa aaa 1
b bb bbb 2
c cc ccc
d dd ddd 4
e ee eee 5
[root@localhost test]# cat test1
a aa aaa 1
b bb bbb 2
c cc ccc 3
d dd ddd 4
e ee eee 5

解析:当读取第一个文件的A的时候NR 和 FNR 都是从1开始计数,这时NR==FNR 将行全部内容赋值给数组,当读取到第二个文件时,NR!=FNR此时表示已读取到第二个文件,将的内容和$0进行比较如果不相同,则输出行号。

FS
输入字段分割符,默认是以空格为分隔符,在日常中常常文本里面不都以空格分隔,此时就要指定分割符来格式化输入。

[root@localhost test]# cat test4
a,b,c
d,e,f
g,h,i
j,k,l
[root@localhost test]# awk '{print $1}' test4
a,b,c
d,e,f
g,h,i
j,k,l
[root@localhost test]# awk 'BEGIN{FS=","}{print $1}' test4

以上,test4里面字母间是以“,” 来分割的,第一种写法,由于,没有指定FS,awk默认是以空格来分割,所以全部内容都当作$1来显示,第二个指定FS以“,”分割,所以能够正常打印。

OFS
输出字段分割符,默认为空格,如果读进来的数据是以空格分割,为了需求可能要求输出是以“-“分割,可以使用OFS进行格式化输出

[root@localhost test]# awk 'BEGIN{FS=" ";OFS="---"}{print $1,$2,$3}' test
a---aa---aaa
b---bb---bbb
c---cc---ccc
d---dd---ddd
e---ee---eee

输入行分隔符,判断输入部分的行的起始位置,默认是换行符

[root@localhost test]# cat test4
a,b,c
d,e,f
g,h,i
j,k,l
[root@localhost test]# awk 'BEGIN{RS=","}{print}' test4
a
b
c
d
e
f
g
h
i
j
k
l

这里说明一下,RS=“,”将以,为分割当作一行,即a,b a被当作一行,b也被当作一行,但是细心的会发现以“,”分割c和d之间是没有“,“的为什么也当作一行了呢,是因为输入中c后面还有一个换行符\n 即,输入应该是a,b,c\n只不过\n我们看不到,输入中,a一行,b一行,c\nd一行但是输出的时候系统会将\n视为换行符,所以看上去c和d是两行,实际上是一行

ORS
输出行分割符,默认的是换行符,它的机制和OFS机制一样,对输出格式有要求时,可以进行格式化输出

[root@localhost test]# awk 'BEGIN{ORS=","}{print}' test4
a,b,c,d,e,f,g,h,i,j,k,l,

全部的分割符,都变成了”,“,具体的格式,可以根据实际需求,进行多种变化。

原文链接:https://blog.csdn.net/qq_41673534/article/details/80252016