Bash 查找多个文件的公用行
我有近200个文件,我想找到所有200个文件共有的行,行如下:Bash 查找多个文件的公用行,bash,shell,awk,sed,Bash,Shell,Awk,Sed,我有近200个文件,我想找到所有200个文件共有的行,行如下: HISEQ1:105:C0A57ACXX:2:1101:10000:105587/1 HISEQ1:105:C0A57ACXX:2:1101:10000:105587/2 HISEQ1:105:C0A57ACXX:2:1101:10000:121322/1 HISEQ1:105:C0A57ACXX:2:1101:10000:121322/2 HISEQ1:105:C0A57ACXX:2:1101:10000:12798/1 HISE
HISEQ1:105:C0A57ACXX:2:1101:10000:105587/1
HISEQ1:105:C0A57ACXX:2:1101:10000:105587/2
HISEQ1:105:C0A57ACXX:2:1101:10000:121322/1
HISEQ1:105:C0A57ACXX:2:1101:10000:121322/2
HISEQ1:105:C0A57ACXX:2:1101:10000:12798/1
HISEQ1:105:C0A57ACXX:2:1101:10000:12798/2
有没有一种方法可以以批处理的方式完成此任务?我认为没有一个unix命令可以直接用于此任务。但是您可以围绕
comm
和grep
命令创建一个小shell脚本,如下例所示:
#!/bin/bash
# Prepare 200 (small) test files
rm data-*.txt
for i in {1..200} ; do
echo "${i}" >> "data-${i}.txt"
# common line
echo "foo common line" >> "data-${i}.txt"
done
# Get the common lines between file1 and file2.
# file1 and file2 can be random files out of the set,
# ideally they are the smallest ones
comm -12 data-1.txt data-2.txt > common_lines
# Now grep through the remaining files for those lines
for file in data-{3..100}.txt ; do
# For each remaining file reduce the common_lines to those
# which are found in that file
grep -Fxf common_lines "${file}" > tmp_common_lines \
&& mv tmp_common_lines > common_lines
done
# Print the common lines
cat common_lines
同样的方法也可以用于更大的文件。这将花费更长的时间,但内存消耗保持线性
awk '(NR==FNR){a[$0]=1;next}
(FNR==1){ for(i in a) if(a[i]) {a[i]=0} else {delete a[i]} }
($0 in a) { a[$0]=1 }
END{for (i in a) if (a[i]) print i}' file1 file2 file3 ... file200
此方法逐行处理每个文件。其思想是通过使用关联数组a[line]
来跟踪当前文件中看到的行。1表示该行在当前文件中可见,0表示该行不可见
(NR==FNR){a[$0]=1;next}
将第一个文件存储到按行索引的数组中,并将其标记为可见(NR==FNR)
是用于检查第一行的条件李>
(FNR==1){for(i in a)if(a[i]){a[i]=0}else{delete a[i]}
:如果我们读取了文件的第一行,请检查在上一个文件中看到了哪些行。如果未看到数组中的行,请将其删除;如果已看到,请将其重置为未看到(0
)。这样,我们可以清理内存并在单个文件中处理重复的行(a中的$0){a[$0]=1}
:每行,检查该行是否是数组的成员,如果是,则将其标记为可见(1
)END{for(a中的i)if(a[i])print i}
:处理完所有行后,检查要打印的行你能试试下面的吗。公平警告,这将消耗内存,因为数据正在存储到数组中
awk '
FNR==1{
file++
}
{
a[$0]++
}
END{
for(i in a){
if(a[i]==file){
print "Line " i " is found in all "file " files."
}
}
}' file1 file2 ....file200
我的方法是生成一个超级文件,在文件名和行号的开头有一列,然后是相应的内容行,在内容列上对该文件进行排序
Grep可以生成第一部分,特别是如果您可以排除文件的某些部分,那么我们鼓励用户增加他们为解决自己的问题所付出的努力,因此请在您的问题中添加他们,然后让我们知道。此外,请提及您希望遍历和检查详细信息的文件格式。好的,已还原。对于OP:我建议使用awk,如下所示。但是,也许出于教育目的,
grep
和comm
的使用仍然很有趣。谢谢,我也尝试过类似的方法。你能解释一下awk之后的所有这些是什么意思吗?我还需要列出我所有的200个文件吗?是的,非常感谢hek2mgl,我不经常使用这种样式,所以它肯定非常有用…@user3224522您可以使用shell扩展来避免手动列出所有200个文件。例如,如果文件名为file1.dat file2.dat,则可以执行awk''文件*.dat
。shell将在调用awk之前展开文件名。@user3224522抱歉代码中有一个小错误。现在已修复。我已检查此功能是否正常,可能我的文件没有任何共同行…:/这可能有问题。假设您有200个1GB的文件,但没有一行是相同的。您将尝试在阵列a
@kvantour中存储200GB的数据,并在其中添加了一条警告,如果内存足够,那么这应该是最简单的一条。