如何从文件中删除重复行?

17

我有一个工具可以生成测试并预测输出。我的想法是,如果出现故障,我可以将预测结果与实际输出进行比较,以查看它们的差异。问题在于,实际输出会包含一些重复的行,这会让 diff 感到困惑。因此,我想要去除重复行,以便轻松地进行比较。基本上,就像 sort -u,但不需要排序。

是否有任何 Unix 命令行工具可以做到这一点?


可能是重复问题,参考如何在Unix中删除文件中的重复行? - Ciro Santilli OurBigBook.com
5个回答

25

和使用uniq的答案相反,它们在你不介意先对文件进行sort排序时效果很好。如果您需要删除非相邻行(或者想要删除重复行而不重新排列文件),则以下Perl单行代码应该可以解决问题(从这里借来):

cat textfile | perl -ne '$H{$_}++ or print'

我觉得这是一个很棒的答案。我已经用Perl编程大约6年了,从来没有想过能有如此简洁的解决办法。 - Xetius
1
Perl的部分真的很不错。但是,它确实有资格获得“使用cat命令毫无意义奖” :-) (请参见http://partmaps.org/era/unix/award.html)。只需在结尾处使用“<textfile”。 - sleske
2
我从未听说过那个奖项!是的,有时我会过度使用cat命令;我不知道为什么“cat x |”看起来比“< x”更好..但它确实如此 :) 这可能与我经常重定向stdout有关,“./prog < x > y”让我眼花缭乱 :P - Matt J
4
无用的cat奖项!使用perl -ne ...任何内容...文本文件 - Bklyn
1
为了从未排序的输入中仅获取非唯一行,可以基于@MattJ的答案使用以下命令:perl -ne '0==$H{$_}++ or print'。请注意,它将打印第二次出现的行——也就是第一个重复的行。 - Joel Purra
显示剩余2条评论

21

uniq(1)

概要

uniq [选项]... [输入文件 [输出文件]]

说明

从输入文件(或标准输入)中仅保留连续的相同行中的一行,并写入输出文件(或标准输出)。

如果您想去掉非相邻重复的行,这个 Perl 片段也可以实现:

while(<>) {
    print $_ if (!$seen{$_});
    $seen{$_}=1;
}

Perl的答案只适用于您想要第一个项目的情况。最后一个项目需要不同的解决方案。 - Xetius
1
对于那些不知道如何使用Perl的人,这是您需要键入的全部内容:perl -pe 'print unless $seen{$_}++' [输入] > 输出 - reinierpost
@Xetuis,它们是同一行 :) 如果您确实想要最后一行,请将已查看的条目设置为行号,不要在循环中打印,然后按行号顺序打印它们。但我认为在这种情况下不需要这样做。 - The Archetypal Paul
@reinierpost,是的,我永远记不住用命令行选项来做那件事情,所以我倾向于使用完整的脚本... - The Archetypal Paul

3

如果环境不允许使用Perl(我还没有见过这种情况),这里提供了一个awk实现。注意:如果有多个重复的行,则会打印重复的输出。

awk '{

# Cut out the key on which duplicates are to be determined.
key = substr($0,2,14)

#If the key is not seen before, store in array,else print
if ( ! s[key] )
    s[key] = 1;
else
    print key;
}'

4
如果你仅仅看整行作为关键字,那么这与Perl解决方案类似:awk '!c[$0]++' file - glenn jackman

1

如果您想要删除相邻的重复行,请使用uniq

如果您想要删除所有重复行,而不仅仅是相邻的行,则需要更加复杂。


1

这是我在等待答案时想出来的(尽管第一个(并被接受的)答案大约在2分钟内到来)。我在VIM中使用了这个替换:

%s/^\(.*\)\n\1$/\1/

这意味着:查找在换行符后面与之前相同的行,并仅用我们在第一行捕获的内容替换它们。

uniq 明显更容易实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接