用 AWK 处理多文件输入

很多人通过发布以下解决方案来帮助 AWK 同时处理多个输入文件:

$ awk 'FNR==NR{a[$1]=$2 FS $3;next}{ print $0, a[$1]}' file2 file1

这个很好用,但是我想知道是否有人可以向我解释一下为什么?我发现 AWK 语法有点难以掌握,希望有人不介意为我分解代码片段。

97754 次浏览
awk 'FNR==NR{a[$1]=$2 FS $3;next}

这里我们处理第一个输入(file2)。比方说,FS 是空格,我们构建一个数组(a) ,索引是 column 1,值是 column2 " " column3FNR==NR and next的意思是,这部分代码只对 file2有效。你可以看看什么是 NR 和 FNR

{ print $0, a[$1]}' file2 file1

NR != FNR时处理第二个输入 file1。在这里,我们打印 file1行,并以 column 1为索引,找出 array (a) print 中的值。换句话说,file1和 file2在这两个文件中都是由 column 1联接的。

NR 和 FNR,

1st input has 5 lines
2nd input has 10 lines,


NR would be 1,2,3...15
FNR would be 1...5 then 1...10

你看到了 FNR==NR检查的诀窍。

我在谷歌上找到了这个问题/答案,它似乎指的是在另一个问题(如何使用 AWK 合并两个文件?)中找到的一个非常具体的数据集。下面是我一直在寻找的答案(我认为大多数人都会这么做) ,也就是说,只需要使用 AWK 将两个不同文件中的每一行连接起来。虽然您可能会使用一些 UNIX 实用程序,如 加入浆糊,但是如果您想要的输出不同,AWK 显然会更加灵活和强大,比如使用 如果语句,或者更改 OFS(根据实用程序的不同,这可能更加困难; 参见下文) ,以一种更具表现力的方式更改输出(对于 shell 脚本程序来说,这是一个重要的考虑因素)

对于简单的逐行连接:

awk 'FNR==NR { a[FNR""] = $0; next } { print a[FNR""], $0 }' file1 file2

这通过使用隐式类型转换来模拟数字索引数组(AWK 只有关联数组)的函数。这是相对表达和容易理解。

使用两个名为 test1和 test2的文件,其代码行如下:

Test1:

line one
line two
line three

Test2:

line four
line five
line six

我得到的结果是:

line one line four
line two line five
line three line six

根据您希望如何连接输出中各列之间的值,可以选择适当的输出字段分隔符。下面是一个使用椭圆(...)分隔列的示例:

awk 'BEGIN { OFS="..."} FNR==NR { a[(FNR"")] = $0; next } { print a[(FNR"")], $0 }' test1 test2

产生这样的结果:

line one...line four
line two...line five
line three...line six

我希望这至少能激励你们所有人充分利用 AWK 的力量!

不久前,我偶然发现了一个非常好的解决方案,可以同时处理多个文件。方法是使用以下方法在内存中保存 AWK 数组中的文件:

FILENAME==ARGV[1] {  file2array[FNR] = $0 ; next }
FILENAME==ARGV[2] {  file1array[FNR] = $0 ; next }

对于后期数据处理,最好节省行数,这样:

FILENAME==ARGV[1] {  file2array[FNR] = $0 ; f2rows = FNR ; next }
FILENAME==ARGV[2] {  file1array[FNR] = $0 ; f1rows = FNR ; next }

f2rowsf1rows将保持最后一行的位置。

它有更多的代码,但是如果您想要更复杂的数据处理,我认为这是更好的方法。此外,以前的方法是按顺序处理输入的,因此如果需要同时进行一些依赖于两个文件的数据的计算,那么就不能这样做,而使用这种方法可以同时处理两个文件的所有内容。