根据特定列从文本文件中过滤唯一数据,无需排序

根据特定列从文本文件中过滤唯一数据,无需排序

我有各种 10-100k 行的文本文件,格式如下。

"2018-12-07 23:21:32",XX,99,ZZZ,250,REMOVED
"2018-12-07 23:25:17",XX,99,ZZZ,250,AVAILBLE
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED

在上面的示例中,您可以看到有 3 条记录,其中第 2、3 和 4 列相同(XX,99,ZZZ - 第 1/2/6 行)。我需要删除前两行,只保留最后一行。

期望的输出如下所示。

"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED

我有一个 PHP 脚本,但对于 100k~ 行的文件来说,速度非常慢,而且出现内存错误。

答案1

删除一系列重复项中除第一个以外的所有内容比删除除最后一个之外的所有内容更容易 - 您可以尝试类似的操作

$ tac file | awk -F, '!seen[$2 FS $3 FS $4]++' | tac
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED

答案2

BEGIN { FS = "," }

FNR == NR {
    if (seen[$2,$3,$4])
        delete lines[seen[$2,$3,$4]]

    lines[FNR]
    seen[$2,$3,$4] = FNR

    next
}

FNR in lines

awk程序期望读取同一文件两次。第一次读取文件时,仅FNR == NR执行块。这会记住lines要输出的行号,作为数组中的键。如果已经看到具有第二、第三和第四列的特定组合的行,则将最近的行号作为键插入,并删除前一个(语句delete

在第二次解析文件期间,所发生的只是在数组中查找当前行号lines。如果找到,则打印该行。

使用相同代码的“单行”版本运行的示例:

$ awk -F, 'FNR==NR { if(s[$2,$3,$4]) delete l[s[$2,$3,$4]]; l[FNR]; s[$2,$3,$4]=FNR; next}; FNR in l' file file
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED

相关内容