什么是NR和FNR,“ NR == FNR”意味着什么?


83

我正在使用来学习文件比较awk

我发现如下语法

awk 'NR==FNR{a[$1];next}$1 in a{print $1}' file1 file2

我不明白这有什么意义NR==FNR?如果我尝试,FNR==NR那么我也会得到相同的输出吗?

它到底是做什么的?


20
如果a==bb==a产生相同的结果,您会感到惊讶吗?
Ed Morton

5
请参见Two-file Processingbackreference.org/2010/02/10/idiomatic-awk
伊唐赖斯纳

Answers:


91

在awk中,FNR指的是当前文件中的记录号(通常是行号),并NR指的是总记录号。该运算符==是一个比较运算符,当两个周围的操作数相等时返回true。

这意味着该条件NR==FNR仅对第一个文件成立,因为FNR每个文件的第一行都重置为1,但NR仍在不断增加。

此模式通常用于仅对第一个文件执行操作。该next块内部意味着将跳过所有其他命令,因此它们仅在第一个文件以外的文件上运行。

条件FNR==NR将与比较两个相同的操作数NR==FNR,因此它的行为方式相同。


3
“ =“有时用于测试相等性,有时用于进行赋值。如果将双等号用于分配,则FNR == NR将与NR == FNR不同。因此,对于像awk这样不熟悉awk的人来说,询问他们是否相同似乎是合理的。
托德·沃尔顿

@ToddWalton好点!另一个例子:a='3x'; if [[ $a == 3* ]]; then echo yes; fi您不能同时切换的两侧==
沃尔特A

@WalterA是的(至少在Bash中)。您对我的答案有何建议?
Tom Fenech '18

1
不,您的答案很好。我非常喜欢看到社区同样喜欢我们的答案。我们使用不同的样式,两者都被认为非常有用。我只是给了你一个赞,所以目前我们有相同数量的赞。
沃尔特A

70

在文件2中查找也在文件1中的键(行的第一个单词)。
步骤1:使用文件1的前几个字填充数组a:

awk '{a[$1];}' file1

步骤2:在同一命令中填充数组a,并忽略文件2。为此,请检查到目前为止的记录总数以及当前输入文件的编号。

awk 'NR==FNR{a[$1]}' file1 file2

步骤3:忽略}解析文件1时可能发生的操作

awk 'NR==FNR{a[$1];next}' file1 file2 

步骤4:在阵列a中找到时打印file2的键

awk 'NR==FNR{a[$1];next} $1 in a{print $1}' file1 file2

4
这种单线的出色拆卸。步骤1中的分号是否必要?
Tomasz Gandor

2
@TomaszGandor在步骤1中不需要分号。我可以在步骤3;next中添加next分号,但这是一个奇怪的添加(例如在步骤3中添加并需要分号)。您可以使用测试第1步awk '{a[$1]} END { for (k in a) { print "a[k]=" k } }' file1
Walter A

43

在awk手册中查找NR并查询FNR自己,然后NR==FNR在以下示例中询问自己处于何种情况:

$ cat file1
a
b
c

$ cat file2
d
e

$ awk '{print FILENAME, NR, FNR, $0}' file1 file2
file1 1 1 a
file1 2 2 b
file1 3 3 c
file2 4 1 d
file2 5 2 e

是否还可以打印正在处理的文件的编号?有内置变量吗?(我知道我们可以为此创建一个变量,并且每次NR为1时都将其递增)
LEo

在GNU awk中,该变量是ARGIND,否则可以执行FNR==1{ print ++file_nr }
Ed Morton

如果可以的话,用另一个问题回答问题不是那么有效;)
Florian Castelain

我没有问任何问题,而是向我展示了如何获得OPs问题的答案。
Ed Morton

20

awk内置变量。

NR -它提供了已处理记录的总数。

FNR -它给出每个输入文件的记录总数。


14

假设您有文件a.txt和b.txt与

cat a.txt
a
b
c
d
1
3
5
cat b.txt
a
1
2
6
7

请记住,NR和FNR是awk内置变量。NR-给出已处理记录的总数。(在这种情况下,a.txt和b.txt中都包含)FNR-给出每个输入文件的记录总数(a.txt或b.txt中的记录)

awk 'NR==FNR{a[$0];}{if($0 in a)print FILENAME " " NR " " FNR " " $0}' a.txt b.txt
a.txt 1 1 a
a.txt 2 2 b
a.txt 3 3 c
a.txt 4 4 d
a.txt 5 5 1
a.txt 6 6 3
a.txt 7 7 5
b.txt 8 1 a
b.txt 9 2 1

让“添加下一个”跳过与NR == FNR匹配的第一个

在b.txt和a.txt中

awk 'NR==FNR{a[$0];next}{if($0 in a)print FILENAME " " NR " " FNR " " $0}' a.txt b.txt
b.txt 8 1 a
b.txt 9 2 1

在b.txt中,但不在a.txt中

 awk 'NR==FNR{a[$0];next}{if(!($0 in a))print FILENAME " " NR " " FNR " " $0}' a.txt b.txt
b.txt 10 3 2
b.txt 11 4 6
b.txt 12 5 7

awk 'NR==FNR{a[$0];next}!($0 in a)' a.txt b.txt
2
6
7
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.