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
答案 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)
您只需使用grep
和sort
DATAFILE=file.dat
for match in $(grep -P '(!\w+!)' -o "$DATAFILE" | sort -u); do
grep -m1 "$match" "$DATAFILE";
done
输出:
foo!bar!baz
!baz!quix