use*_*365 20 perl shell-script text-processing
我使用的是 Solaris 10,因此涉及 -f 的 grep 选项不起作用。
我有两个管道分隔的文件:
文件 1:
abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|
Run Code Online (Sandbox Code Playgroud)
文件2:
abc|123|
kumar|pki|
cab|234
Run Code Online (Sandbox Code Playgroud)
我想将 file2 的前两列与 file1 进行比较(在前两列中搜索 file1 的全部内容),如果它们匹配打印 file1 的匹配行。然后搜索文件 2 的第二行,依此类推。
预期输出:
abc|123|BNY|apple|
cab|234|cyx|orange|
Run Code Online (Sandbox Code Playgroud)
我拥有的文件很大,包含大约 400,000 行,所以我想让执行速度更快。
ter*_*don 23
这就是 awk 的设计目的:
$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|
Run Code Online (Sandbox Code Playgroud)
-F'|'
: 将字段分隔符设置为|
.NR==FNR
: NR 是当前输入的行号,FNR 是当前文件的行号。只有在读取第一个文件时,两者才会相等。c[$1$2]++; next
:如果这是第一个文件,则保存c
数组中的第一个两个字段。然后,跳到下一行,以便这仅应用于第一个文件。
c[$1$2]>0
: else 块仅在这是第二个文件时才会执行,因此我们检查该文件的字段 1 和 2 是否已经被看到 ( c[$1$2]>0
),如果已经看到,我们将打印该行。在 中awk
,默认操作是打印该行,因此如果c[$1$2]>0
为 true,则将打印该行。
或者,由于您使用 Perl 进行了标记:
$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|
Run Code Online (Sandbox Code Playgroud)
第一行将打开file2
,读取直到第二个|
( .+?\|[^|]+
) 的所有内容并将其(这$&
是最后一个匹配运算符的结果)保存在%k
哈希中。
第二行处理 file1,使用相同的正则表达式提取第一两列,如果这些列在%k
散列中定义,则打印该行。
上述两种方法都需要将 file2 的前 2 列保存在内存中。如果你只有几十万行,那应该不是问题,但如果是,你可以做类似的事情
cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done
Run Code Online (Sandbox Code Playgroud)
但这会更慢。
我认为
grep -Ff file2 file1
Run Code Online (Sandbox Code Playgroud)
这就是您正在寻找的。它应该是有效的,但我不确定它会像你想要的那样准确。如果abc|123
(例如)在file1
不同列的一行中找到,则该行也将被打印。如果你能保证这种情况永远不会发生,那么上面的代码应该可以工作。