Bash 查找多个文件的公用行

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

我有近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
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的数据,并在其中添加了一条警告,如果内存足够,那么这应该是最简单的一条。