2014-09-10 65 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 

结果将不会在任何特定的顺序。