我有几个文件,每一列,我想将它们彼此进行比较,以找出所有文件中包含的元素。或者 - 如果它更容易 - 我可以制作一个列矩阵。
如何在多列中找到公共元素。
我不是awk的专家(显然)。因此,非常感谢对代码的详细解释。
@ joepvd制作了一些类似的代码... https://unix.stackexchange.com/questions/216511/comparing-the-first-column-of-two-files-and-printing-the-entire-row-of-the-secon/216515#216515?newreg=f4fd3a8743aa4210863f2ef527d0838b
答案 0 :(得分:2)
当你猜到时,查找所有文件中包含的元素
awk
是你的朋友。请使用以下步骤
#Store the files in an array. Assuming all files in one place
filelist=( $(find . -maxdepth 1 -type f) ) #array of files
awk -v count="${#filelist[@]}" '{value[$1]++}END{for(i in value){
if(value[i]==count){printf "Value %d is found in all files\n",i}}}' "${filelist[@]}"
注意强>
-v count="${#filelist[@]}"
将总文件数传递给awk
注意数组开头的#
给出了元素数。value[$1]++
增加文件中显示的值的计数。如果初始值为零,它还会创建value[$1]
。END
块仅在最后执行,即在处理完所有文件的每个记录之后。答案 1 :(得分:0)
如果您可以在一个文件中多次使用相同的值,我们需要注意每个文件只计算一次。
GNU awk的一些变体(ARGIND
需要它可用。可以通过检查FILENAME
来模拟,但这甚至更难。)
gawk '{ A[$0] = or(A[$0], lshift(1, ARGIND-1)) }
END { for (x in A) if (A[x] == lshift(1, ARGIND) - 1) print x }'
file1 file2 file3
数组A
由值(行)键控,并保存已找到行的文件的位图。对于每行读取,我们设置位号ARGIND-1
(因为ARGIND
以1开头)。
在输入结束时,遍历所有已保存的行,如果位图全部为1,则打印它们(最多可达到所看到的文件数)。
gawk 'ARGIND > LASTIND {
LASTIND = ARGIND; for (x in CURR) { ALL[x] += 1; delete CURR[x] }
}
{ CURR[$0] = 1 }
END { for (x in CURR) ALL[x] += 1;
for (x in ALL) if (ALL[x] == ARGIND) print x
}' file1 file2 file3
这里,当遇到一行时,设置数组CURR
中的相应元素(中间部分)。当文件编号更改(ARGIND > LASTIND
)时,对于ALL
中设置的所有值,数组CURR
中的值会增加,后者将被清除。在输入的END
处,ALL
中的值将针对最后一个文件进行更新,并根据文件总数检查总计数,打印出现在所有文件中的文件。
对于大输入,位图方法可能稍快一些,因为它不涉及创建和遍历临时数组,但它可以处理的文件数量受位操作可以处理的位数限制(似乎在64位Linux上大约有50个。)
在这两种情况下,由此产生的打印输出基本上是随机顺序,因为关联数组不会保留排序。
答案 2 :(得分:0)
我会假设它是重要的问题,而不是实施语言,所以这里使用perl
作为替代方案:
#! /usr/bin/perl
use strict;
my %elements=();
my $filecount=@ARGV;
while(<>) {
$elements{$_}->{$ARGV}++;
};
print grep {!/^$/} map {
"$_" if (keys %{ $elements{$_} } == $filecount)
} (keys %elements);
while
循环构建哈希散列(又名&#34; HoH&#34;。有关详细信息,请参阅man perldsc
和man perllol
。另请参阅下面的示例) ,顶级键是每个输入文件的每一行,第二级键是值出现的文件的名称。
grep ... map {...}
返回每个顶级键,其中出现的文件数等于输入文件的数量
这里是数据结构的样子,使用你给ilkkachu的例子:
{
'A' => { 'file1' => 1 },
'B' => { 'file2' => 1 },
'C' => { 'file1' => 1, 'file2' => 1, 'file3' => 1 },
'E' => { 'file2' => 1 },
'F' => { 'file1' => 1 },
'K' => { 'file3' => 1 },
'L' => { 'file3' => 1 }
}
请注意,如果单个文件中出现任何重复项,则该事实存储在此结构中并可以进行检查。
在此特定示例中,grep
之前的map
并非严格要求,但如果您希望将结果存储在数组中以供进一步处理而不是立即打印,则非常有用。
使用grep
,它只返回一个匹配元素的数组,或者在这种情况下只返回单个值C
。没有它,它返回一个空字符串数组加上匹配的元素。例如("", "", "", "", "C", "", "")
。实际上,他们最后会返回带有换行符(\n
)的元素,因为我在chomp
循环中没有使用while
,因为我知道我正在打印他们直接。在大多数程序中,我使用chomp
来删除换行符和/或回车。