哇哦;当两个文件共享一个公共 header 时从两个文件中获取多行
awk; getting multiple lines from two files when they share a common header
我有一个问题与有关此主题的许多其他问题非常相似,但我无法将这些解决方案扩展到我正在寻找的确切输出。
我有两个以 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
每个 'block' 有四行,其中第一行(header)总是以 @ 开头并包含一个 id-number(例如 0001)和一个索引(即 1 或 2在 'space') 之后。
每个 id-number 都应在具有两个索引的同一文件中出现两次(如上例中除 0002 之外的所有 id-number 都是如此)。
现在我想把id-number出现在两个文件中的块分开存储(表示在任一文件中只出现一次的块)。
在这种情况下,输出应该是:
@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[]; next}
in lines {x=NR+3}
(NR<=x) {print [=14=]}' file2.txt file1.txt
这输出:
@header:with:id:number:0002 2:this:number:indicates:pair:number
PQRS
+
9012
到一半了。
我的问题是,如何在两个文件中出现的header中搜索id-number,并将它们存储在第三个文件中并从两个原始文件中删除相应的块?
您可以使用此 gnu awk
打印每个文件只出现一次的所有 headers:
awk -v ORS= -v RS='@header:' -F '[:[:blank:]]+' 'NF {
if ( in seen)
delete seen[]
else
seen[] = prt [=10=]
}
ENDFILE {
for (i in seen)
print seen[i]
delete seen
}
{prt = RT}' file1 file2
@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
使用 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([=10=],map,":"); # Split the record into array map using ":" as the delimiter
map1[substr(map[5],1,4)]=[=10=] # 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([=10=],map,":");
id=substr(map[5],1,4); # id e.g. 0002
if (id in map1) {
print [=10=]; # 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([=11=],map,":");map1[substr(map[5],1,4)]=[=11=] } NR!=FNR { ORS="@header";split([=11=],map,":");id=substr(map[5],1,4);if (id in map1) { print [=11=];print map1[id] } }' file1.txt file2.txt
您能否尝试按照显示的示例进行编写和测试,我相信应该可以在任何 awk
中工作,但只能在 GNU awk
中进行测试。
awk '
FNR==NR{
if([=10=]~/^@/){
match([=10=],/^@header:with:id:number:[0-9]{4}/)
mat1=substr([=10=],RSTART,RLENGTH)
arr1[mat1]++
}
val1[mat1]=(val1[mat1]?val1[mat1] ORS:"")[=10=]
next
}
{
if([=10=]~/^@/){
match([=10=],/^@header:with:id:number:[0-9]{4}/)
mat2=substr([=10=],RSTART,RLENGTH)
arr2[mat2]++
}
val2[mat2]=(val2[mat2]?val2[mat2] ORS:"")[=10=]
}
END{
for(key1 in arr1){
if(arr1[key1]==1 && arr2[key1]==1){print val1[key1] ORS val2[key1] }
}
}' file1.txt file2.txt
这将在两个文件中查找匹配索引的计数为 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
我有一个问题与有关此主题的许多其他问题非常相似,但我无法将这些解决方案扩展到我正在寻找的确切输出。
我有两个以 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
每个 'block' 有四行,其中第一行(header)总是以 @ 开头并包含一个 id-number(例如 0001)和一个索引(即 1 或 2在 'space') 之后。 每个 id-number 都应在具有两个索引的同一文件中出现两次(如上例中除 0002 之外的所有 id-number 都是如此)。 现在我想把id-number出现在两个文件中的块分开存储(表示在任一文件中只出现一次的块)。
在这种情况下,输出应该是:
@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[]; next}
in lines {x=NR+3}
(NR<=x) {print [=14=]}' file2.txt file1.txt
这输出:
@header:with:id:number:0002 2:this:number:indicates:pair:number
PQRS
+
9012
到一半了。
我的问题是,如何在两个文件中出现的header中搜索id-number,并将它们存储在第三个文件中并从两个原始文件中删除相应的块?
您可以使用此 gnu awk
打印每个文件只出现一次的所有 headers:
awk -v ORS= -v RS='@header:' -F '[:[:blank:]]+' 'NF {
if ( in seen)
delete seen[]
else
seen[] = prt [=10=]
}
ENDFILE {
for (i in seen)
print seen[i]
delete seen
}
{prt = RT}' file1 file2
@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
使用 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([=10=],map,":"); # Split the record into array map using ":" as the delimiter
map1[substr(map[5],1,4)]=[=10=] # 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([=10=],map,":");
id=substr(map[5],1,4); # id e.g. 0002
if (id in map1) {
print [=10=]; # 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([=11=],map,":");map1[substr(map[5],1,4)]=[=11=] } NR!=FNR { ORS="@header";split([=11=],map,":");id=substr(map[5],1,4);if (id in map1) { print [=11=];print map1[id] } }' file1.txt file2.txt
您能否尝试按照显示的示例进行编写和测试,我相信应该可以在任何 awk
中工作,但只能在 GNU awk
中进行测试。
awk '
FNR==NR{
if([=10=]~/^@/){
match([=10=],/^@header:with:id:number:[0-9]{4}/)
mat1=substr([=10=],RSTART,RLENGTH)
arr1[mat1]++
}
val1[mat1]=(val1[mat1]?val1[mat1] ORS:"")[=10=]
next
}
{
if([=10=]~/^@/){
match([=10=],/^@header:with:id:number:[0-9]{4}/)
mat2=substr([=10=],RSTART,RLENGTH)
arr2[mat2]++
}
val2[mat2]=(val2[mat2]?val2[mat2] ORS:"")[=10=]
}
END{
for(key1 in arr1){
if(arr1[key1]==1 && arr2[key1]==1){print val1[key1] ORS val2[key1] }
}
}' file1.txt file2.txt
这将在两个文件中查找匹配索引的计数为 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