awk;当两个文件共享一个公共头时,从其中获取多行

awk;当两个文件共享一个公共头时,从其中获取多行,awk,fastq,Awk,Fastq,我有一个问题与关于这个主题的许多其他问题非常相似,但我无法将这些解决方案扩展到我正在寻找的确切输出 我有两个格式为fastq样式的文件,如下所示: file1.txt @header:with:id:number:0001 1:this:number:indicates:pair:number ABCD + 1324 @header:with:id:number:0001 2:this:number:indicates:pair:number EFGH + 5678 @header:with:i

我有一个问题与关于这个主题的许多其他问题非常相似,但我无法将这些解决方案扩展到我正在寻找的确切输出

我有两个格式为fastq样式的文件,如下所示:

file1.txt

@header:with:id:number:0001 1:this:number:indicates:pair:number
ABCD
+
1324
@header:with:id:number:0001 2:this:number:indicates:pair:number
EFGH
+
5678
@header:with:id:number:0002 2:this:number:indicates:pair:number
PQRS
+
9012
@header:with:id:number:0003 1:this:number:indicates:pair:number
IJKL
+
3456
@header:with:id:number:0003 2:this:number:indicates:pair:number
MNOP
+
7890
file2.txt

@header:with:id:number:0004 1:this:number:indicates:pair:number
QRST
+
1324
@header:with:id:number:0004 2:this:number:indicates:pair:number
UVWX
+
5678
@header:with:id:number:0005 1:this:number:indicates:pair:number
CDEF
+
3456
@header:with:id:number:0005 2:this:number:indicates:pair:number
GHIJ
+
7890
@header:with:id:number:0002 1:this:number:indicates:pair:number
YZAB
+
9012
每个“块”都有四行,头一行始终以@开头,并在“空格”后包括一个id号(如0001)和一个索引(如1或2)。 每个id号都应该在同一个文件中出现两次,并且具有两个索引,就像上面示例中除0002之外的所有id号都是这样。 现在,我想分别存储id号出现在两个文件中的块,这些块表示两个文件中只出现一次的块

在这种情况下,输出应为:

@header:with:id:number:0002 1:this:number:indicates:pair:number
PQRS
+
9012
@header:with:id:number:0002 2:this:number:indicates:pair:number
YZAB
+
9012
这些行应该从原始文件中删除

为此,到目前为止,我已将awk与以下命令一起使用

awk -F" " '/^@/ && NR==FNR {lines[$1]; next}
    $1 in lines {x=NR+3}
    (NR<=x) {print $0}' file2.txt file1.txt
就在半路上

我的问题是,如何在两个文件中出现的标题中搜索id号,将其存储在第三个文件中,并从两个原始文件中删除相应的块?

您可以使用此gnu awk打印每个文件只出现一次的所有标题:

awk-v-ORS=-v-RS='@header:'-F'[:[:blank:]+''NF{ 如果看到4美元 删除[4美元] 其他的 已见[$4]=prt$0 } 结束文件{ 因为我看到了 印刷品见[i] 删除所见 } {prt=RT}文件1文件2 @标题:带:id:编号:0002 2:此:编号:表示:对:编号 PQRS + 9012 @标题:带:id:编号:0002 1:此:编号:指示:对:编号 伊扎布 + 9012 您可以使用此gnu awk打印每个文件只显示一次的所有标题:

awk-v-ORS=-v-RS='@header:'-F'[:[:blank:]+''NF{ 如果看到4美元 删除[4美元] 其他的 已见[$4]=prt$0 } 结束文件{ 因为我看到了 印刷品见[i] 删除所见 } {prt=RT}文件1文件2 @标题:带:id:编号:0002 2:此:编号:表示:对:编号 PQRS + 9012 @标题:带:id:编号:0002 1:此:编号:指示:对:编号 伊扎布 + 9012 使用GNU awk:

awk 'BEGIN { 
             RS="@header" # Set the input record separator
           } 
   FNR==NR { # process the first file
             ORS="@header"; # Set the output record separator
             split($0,map,":"); # Split the record into array map using ":" as the delimiter
             map1[substr(map[5],1,4)]=$0 # map[5] will be e.g 0002 2. We only want 0002 and so use substr to create an index for array map1 with the record as the value
           } 
   NR!=FNR { # process the second file
             ORS="@header";
             split($0,map,":");
             id=substr(map[5],1,4); # id e.g. 0002
             if (id in map1) { 
                               print $0; # If id in map1 array print this record
                               print map1[id] # if id in map1 array print array value
             } 
            }' file1.txt file2.txt
一艘班轮:

awk 'BEGIN { RS="@header" } FNR==NR { ORS="@header";split($0,map,":");map1[substr(map[5],1,4)]=$0 } NR!=FNR { ORS="@header";split($0,map,":");id=substr(map[5],1,4);if (id in map1) { print $0;print map1[id] } }' file1.txt file2.txt
使用GNU awk:

awk 'BEGIN { 
             RS="@header" # Set the input record separator
           } 
   FNR==NR { # process the first file
             ORS="@header"; # Set the output record separator
             split($0,map,":"); # Split the record into array map using ":" as the delimiter
             map1[substr(map[5],1,4)]=$0 # map[5] will be e.g 0002 2. We only want 0002 and so use substr to create an index for array map1 with the record as the value
           } 
   NR!=FNR { # process the second file
             ORS="@header";
             split($0,map,":");
             id=substr(map[5],1,4); # id e.g. 0002
             if (id in map1) { 
                               print $0; # If id in map1 array print this record
                               print map1[id] # if id in map1 array print array value
             } 
            }' file1.txt file2.txt
一艘班轮:

awk 'BEGIN { RS="@header" } FNR==NR { ORS="@header";split($0,map,":");map1[substr(map[5],1,4)]=$0 } NR!=FNR { ORS="@header";split($0,map,":");id=substr(map[5],1,4);if (id in map1) { print $0;print map1[id] } }' file1.txt file2.txt

请您尝试以下,书面和测试显示的样本,应该在任何awk工作,我相信,但可以测试它在GNUAWK只

这将在两个强制文件中查找匹配索引的计数为1,以防您希望在其中一个文件中有1个计数,然后在上述条件下将arr1[key1]==1&&arr2[key1]==1更改为arr1[key2]==1

输出将如下所示的样本

@header:with:id:number:0002 2:this:number:indicates:pair:number
PQRS
+
9012
@header:with:id:number:0002 1:this:number:indicates:pair:number
YZAB
+
9012

请您尝试以下,书面和测试显示的样本,应该在任何awk工作,我相信,但可以测试它在GNUAWK只

这将在两个强制文件中查找匹配索引的计数为1,以防您希望在其中一个文件中有1个计数,然后在上述条件下将arr1[key1]==1&&arr2[key1]==1更改为arr1[key2]==1

输出将如下所示的样本

@header:with:id:number:0002 2:this:number:indicates:pair:number
PQRS
+
9012
@header:with:id:number:0002 1:this:number:indicates:pair:number
YZAB
+
9012

是这种格式吗?如果您明确地标识了这种格式,您就更有可能接触到使用这种格式的人。这听起来像是真的想打印和删除ID在文件中只出现一次的块-这比比较两个文件中的ID来查找两个文件中出现的ID要简单,如果ID总是相同的,那么在一个文件中出现一次。@EdMorton理想情况下,id号在同一个文件中出现两次,一次是索引1,一次是索引2。但是,如果其中一个索引丢失,则预期它会出现在另一个文件中,因此id号会出现在两个文件中。这是由于下游处理步骤中存在一些不确定性,应以不同方式处理这些块,因此我想将它们分开。希望这能澄清你的问题。@tripleee是的,这确实是fastq格式。谢谢你的提示,我将更新问题以明确提及这一点。@MostlyHarmless是的,这就是你在问题中描述的。我的观点是,查找一个在文件中出现一次的ID并从该文件中删除关联的记录比查找两个文件中出现的ID然后从每个文件中删除记录更容易,所以为什么不将此作为您的要求呢?是这种格式吗?如果您明确地标识了这种格式,您就更有可能接触到使用这种格式的人。这听起来像是真的想打印和删除ID在文件中只出现一次的块-这比比较两个文件中的ID来查找两个文件中出现的ID要简单,如果ID总是相同的,那么在一个文件中出现一次。@EdMorton理想情况下,id号在同一个文件中出现两次,一次是索引1,一次是索引2。但是,如果其中一个索引丢失,则预期它会出现在另一个文件中,因此id号会出现在两个文件中。这是由于下游处理步骤中存在一些不确定性,应处理这些区块
d不同,因此我想将它们分开。希望这能澄清你的问题。@tripleee是的,这确实是fastq格式。谢谢你的提示,我将更新问题以明确提及这一点。@MostlyHarmless是的,这就是你在问题中描述的。我的观点是,查找一个在文件中出现一次的ID并从该文件中删除关联的记录比查找两个文件中出现的ID然后从每个文件中删除记录更容易,所以为什么不将此作为您的要求呢?谢谢您的回答!它工作得很好,但据我所知,它并没有显式地查找头是否出现在两个文件中,而是获取在同一个文件中没有一对的所有头。这就是我要找的,如果我的问题不清楚,我很抱歉。++ve提供了很好的解决方案,先生,谢谢分享您的答案!它工作得很好,但据我所知,它并没有显式地查找头是否出现在两个文件中,而是获取在同一个文件中没有一对的所有头。这就是我想要的,如果我的问题不清楚的话,我很抱歉。++ve是一个很好的解决方案,先生,谢谢你的努力。我测试了这个,它给了我预期的答案。我是否正确理解map[5],1,4在被“:”分隔后得到第5个元素,然后1,4得到第5个元素的前4位数字?在这种情况下,我如何将其扩展到查找4个数字,而不是查找任意数量的数字?是的,substr 1,4取第一到第四个字符,您可能可以使用matchmap[5],/^[:digit:]+/;substrmap[5],RSTART,rlength这确实有效,尽管我必须删除“;”在substr争论之前。谢谢你的努力。我测试了这个,它给了我预期的答案。我是否正确理解map[5],1,4在被“:”分隔后得到第5个元素,然后1,4得到第5个元素的前4位数字?在这种情况下,我如何将其扩展到查找4个数字,而不是查找任意数量的数字?是的,substr 1,4取第一到第四个字符,您可能可以使用matchmap[5],/^[:digit:]+/;substrmap[5],RSTART,rlength这确实有效,尽管我必须删除“;”在substr参数之前。