2014-10-29 17 views
3

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 
+0

你有一個更好的例子嗎?不知道如何在不編寫自定義內容的情況下讓該正則表達式按照自己的意願做你想做的事情,但是如果我們能夠看到你的數據的外觀,那麼肯定會有使用一些標準工具的解決方案。 – arco444 2014-10-29 15:07:35

+0

更新,更好? – 2014-10-29 15:16:51

回答

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函數匹配正則表達式的每一行,並返回匹配的TE XT在[a]
  • 每次match成功,我們存儲在一個關聯數組p匹配的文本,並打印
  • 因此有效地獲得uniq功能與regex支持
+0

我得到一個語法錯誤:'context is match($ 0,>>> re,<<<' – 2017-02-03 18:25:54

+0

請確保您使用的gnu-awk寫在我的答案中。 – anubhava 2017-02-03 18:53:42

+0

我在Mac OS上,也許這就是問題 – 2017-02-03 19:12:17

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相匹配,對第一提取組,但你可以$&替換使用整個模式匹配。
這個腳本會過濾掉不正則表達式匹配行,但如果你需要一個不同的行爲,你可以調整它。

+0

Man,StackOverflow真棒。謝謝@LucasTrzesniewski :-) – 2017-02-03 19:43:10

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 
+2

不是值的排序會產生副作用嗎? – 2014-10-29 15:25:36

+0

我不知道「副作用」 - 這會發生。輸入文件有多大?如果你想要更聰明的東西,perl解決方案是完美的。 – arco444 2014-10-29 15:27:10