我有一个文本文件,如:
a b c d e
b c e
d f g e h c
我正在寻找一个简单的AWK,可以在忽略第一个元素的所有行中输出公共元素。所需的输出是:
c e
或
e c
答案 0 :(得分: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)
。
答案 1 :(得分: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
:执行引号后面的代码块。 答案 2 :(得分:1)
另一种perl方法:
perl -lane '
if ($. == 1) { %intersect = map {$_ => 1} @F; next }
%intersect = map {$_ => 1} grep {$intersect{$_}} @F;
END {print join " ", keys %intersect}
' file
结果不会有任何特定的顺序。