仅在许多文件中的特定列上使用grep?

时间:2019-06-21 13:39:30

标签: bash grep

基本上,我有一个带模式的文件,我希望在特定目录下的所有文本文件中搜索每一行。我也只想要完全匹配。许多文件已压缩。

但是,我还有一个条件。我需要模式文件中一行的前两列,以匹配所搜索的任何给定文本文件中一行的前两列。如果它们匹配,则我想要的输出是模式(整行),其后是找到匹配项的文本文件的所有名称以及它们的整个匹配行(不仅仅是前两列)。

输出,例如:

pattern1
file23:"text from entire line in file 23 here"
file37:"text from entire line in file 37 here"
file156:"text from entire line in file 156 here"
pattern2
file12:"text from entire line in file 12 here"
file67:"text from entire line in file 67 here"
file200:"text from entire line in file 200 here"

我知道grep可以获取一个输入文件,但是问题在于,它会获取模式文件中的每个模式,并在移至下一个文件之前在给定的文本文件中搜索它们,这使得上述输出更加困难。因此,我认为最好遍历文件中的每一行,打印该行,然后在多个文件中搜索该行,看看前两列是否匹配。

我想到了这个

cat pattern_file.txt | while read line
do
  echo $line >> output.txt
  zgrep -w -l $line many_files/*txt >> output.txt
done

但是使用此代码,它不会仅按前两列进行搜索。有没有办法为模式行和grep搜索通过的行指定前两列?

做到这一点的最佳方法是什么? grep以外的其他东西(例如awk)会更好用吗?还有其他类似问题,但是没有一个问题同时使用列作为搜索模式和搜索文件。

特征码文件中的几行:

1 5390182 . A C 40.0 PASS DP=21164;EFF=missense_variant(MODERATE|MISSENSE|Aag/Cag|p.Lys22Gln/c.64A>C|359|AT1G15670|protein_coding|CODING|AT1G15670.1|1|1) 
1 5390200 . G T 40.0 PASS DP=21237;EFF=missense_variant(MODERATE|MISSENSE|Gcc/Tcc|p.Ala28Ser/c.82G>T|359|AT1G15670|protein_coding|CODING|AT1G15670.1|1|1) 
1 5390228 . A C 40.0 PASS DP=21317;EFF=missense_variant(MODERATE|MISSENSE|gAa/gCa|p.Glu37Ala/c.110A>C|359|AT1G15670|protein_coding|CODING|AT1G15670.1|1|1) 

搜索到的文件中的几行:

1   10699576    .   G   A   36  PASS    DP=4    GT:GQ:DP    1|1:36:4
1   10699790    .   T   C   40  PASS    DP=6    GT:GQ:DP    1|1:40:6
1   10699808    .   G   A   40  PASS    DP=7    GT:GQ:DP    1|1:40:7

实际上两者都更大。

2 个答案:

答案 0 :(得分:3)

听起来这可能就是您想要的:

awk 'NR==FNR{a[$1,$2]; next} ($1,$2) in a' patternfile anyfile

如果不是,那么请更新您的问题,以清晰,简单地说明您的要求,并提供简洁,可测试的样本输入和预期输出,以证明您的问题,并可以根据您的潜在问题进行测试。

如果anyfile实际上是一个zip文件,那么您将执行以下操作:

zcat anyfile | awk 'NR==FNR{a[$1,$2]; next} ($1,$2) in a' patternfile -

如果使用的不是您要使用的命令,请用{\ x1}}替换zip文件中的文本。

答案 1 :(得分:0)

使用read解析模式文件的列,并将锚添加到zgrep模式:

while read -r column1 column2 rest_of_the_line
do
  echo "$column1 $column2 $rest_of_the_line" 
  zgrep -w -l "^$column1\s*$column2" many_files/*txt
done < pattern_file.txt >> output.txt

read能够将行解析为作为参数传递的多个变量,最后一个获取行的其余部分。它将在$IFS内部字段分隔符的字符周围分隔字段(默认情况下,制表符,空格和换行符可以使用read来替换while IFS='...' read ...命令)。

使用-r可以避免不必要的转义并使解析更加可靠,并且while ... do ... done < file的性能要好一些,因为它可以避免不必要地使用cat。由于while内所有命令的输出都被重定向,因此我也将重定向放在while上,而不是每个单独的命令上。