高级`uniq`与"独特的部分正则表达式"

时间:2014-10-29 14:47:58

标签: regex linux shell awk uniq

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

我在uniq上寻找一个允许输入正则表达式的工具/扩展程序。如果捕获的组对于两条线是相同的,那么这两条线被认为是“等效的”。每个等价类只返回“第一个匹配”。

示例

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

3 个答案:

答案 0 :(得分:2)

不使用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中存储匹配的文字并打印
  • 通过uniq支持
  • 有效地获得regex功能

答案 1 :(得分:2)

这是一个简单的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匹配第一个提取的组,但您可以将其替换为$&以使用整个模式匹配。
此脚本将过滤掉与正则表达式不匹配的行,但如果您需要不同的行为,则可以对其进行调整。

答案 2 :(得分: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