高级“uniq”与“唯一部分正则expression式”

uniq是一种工具,可以一次过滤文件中的行,只显示唯一的行。 uniq有一些支持来指定两行是否“等价”,但是选项是有限的。

我正在寻找uniq上的工具/扩展,允许input一个正则expression式。 如果捕获的组对于两行是相同的,则这两行被认为是“等同的”。 每个等价类只返回“第一个匹配”。

例如

file.dat

 foo!bar!baz !baz!quix !bar!foobar ID!baz! 

使用grep -P '(!\w+!)' -o ,可以提取“独特的部分”:

 !bar! !baz! !bar! !baz! 

这意味着第一行被认为是与第三行相等,而第二行与第四行相等。 因此只有第一个和第二个被打印(第三个和第四个被忽略)。

然后uniq '(!\w+!)' < file.dat应该返回:

 foo!bar!baz !baz!quix 

不使用uniq但使用gnu-awk,你可以得到你想要的结果:

 awk -v re='![[:alnum:]]+!' 'match($0, re, a) && !(a[0] in p) {p[a[0]]; print}' file foo!bar!baz !baz!quix 
  • 使用命令行变量传递所需的正则表达式-v re=...
  • match函数匹配每行的正则表达式,并返回[a]匹配的文本
  • 每次match成功,我们将匹配的文本存储在关联数组p并打印
  • 从而有效地获得了regex支持的uniq功能

这是一个简单的Perl脚本,可以完成这个工作:

 #!/usr/bin/env perl use strict; use warnings; my $re = qr($ARGV[0]); my %matches; while(<STDIN>) { next if $_ !~ $re; print if !$matches{$1}; $matches{$1} = 1; } 

用法:

 $ ./uniq.pl '(!\w+!)' < file.dat foo!bar!baz !baz!quix 

在这里,我使用$1来匹配第一个提取的组,但是您可以用$&替换它以使用整个模式匹配。
这个脚本会过滤出不符合正则表达式的行,但是如果你需要不同的行为,你可以调整它。

你可以用grepsort来做到这一点

 DATAFILE=file.dat for match in $(grep -P '(!\w+!)' -o "$DATAFILE" | sort -u); do grep -m1 "$match" "$DATAFILE"; done 

输出:

 foo!bar!baz !baz!quix