2014-09-10 95 views
1

的所有線路中常見的元素我有這樣一個文本文件:查找文本文件

a b c d e 
b c e 
d f g e h c 

我要尋找一個簡單的AWK可輸出忽略了他們的第一個元素的所有行中的共同元素。所需的輸出是:

c e 

e c 
+0

如果第2行包含「d」會怎麼樣? – 2014-09-10 22:24:16

回答

3
$ cat tst.awk 
FNR==1 { for (i=1; i<=NF; i++) common[$i]; next } 
{ 
    for (c in common) { 
     present = 0 
     for (i=1; i<=NF; i++) { 
      if ($i == c) { 
       present = 1 
      } 
     } 
     if (!present) { 
      delete common[c] 
     } 
    } 
} 
END { 
    i=0 
    for (c in common) { 
     printf "%s%s", (++i>1?OFS:""), c 
    } 
    print "" 
} 
$ awk -f tst.awk file 
c e 

如果你真的想跳過在每一行的第一個字符,只是改變2個for (i=1; i<=NF; i++)環在2,而不是1開始。

儘管上面已經被接受,但我更喜歡@ jaypal的方法(但不是他選擇的工具:-)),所以這裏是awk的等價物:

$ cat tst.awk 
{ delete seen; for (i=1; i<=NF; i++) if (!seen[$i]++) count[$i]++ } 
END { 
    i=0 
    for (c in count) 
     if (count[c] == NR) 
      printf "%s%s", (++i>1?OFS:""), c 
    print "" 
} 
$ 
$ awk -f tst.awk file 
c e 

如果您的awk不支持delete seen,請將其更改爲split("",seen)

3

perl救援:

perl -lane ' 
    my %seen; 
    map { $total{$F[$_]}++ unless $seen{$F[$_]}++ } 1 .. $#F; 
}{ 
    print join " ", grep { $total{$_} == $. } keys %total 
' file 
e c 

保持滾動%total哈希值,只有當他們是每個行獨特的,這將增加的元素。 %seen是一個哈希,幫助跟蹤這些元素。因此我們使用my聲明爲每一行重置它。

END塊中,我們只是grep那些元素的值滿足行總數,這意味着它們在每行上都被看到。

的命令行選項有:

  • -l:在要吃掉換行符期間print地方回來。
  • -a:將空行分割並用這些值加載數組@F
  • -n:創建一個while(<>) { .. }循環來處理每一行。
  • -e:執行引號後面的代碼塊。
+1

+1不錯!方法被盜,並添加到我的答案awk。如果你想偷回來並添加相當於你的awk,請隨意,我會從我的地址中刪除它。 – 2014-09-10 23:27:25

+1

@EdMorton即使我嘗試了,我也無法讓它像你的一樣漂亮! ':''適時upvoted! – 2014-09-10 23:30:07

+1

在Perl中拋棄grep或map的結果被認爲是不好的形式。你可能會考慮用'(1 .. $#F){$ total {$ F [$ _]} ++ ++,除非$ seen {$ F [$ _]} ++}' – 2014-09-11 13:16:32

1

另一個perl的方法:

perl -lane ' 
    if ($. == 1) { %intersect = map {$_ => 1} @F; next } 
    %intersect = map {$_ => 1} grep {$intersect{$_}} @F; 
    END {print join " ", keys %intersect} 
' file 

結果將不會在任何特定的順序。