问题
I have a file that looks as follows :
>sp|rin-1 ghsfdhjkuesl OX=10116 GN=Cdh1 PE=1 SV=1|sp|P10287|ghsfdjdeosd gdhkhs OX=10090 GN=Cdh3 PE=1 SV=2
WRDTANWLEINPETGVISTRAEMDREDSEHVKNSTYTALIIATDDGSPIATGTGTLLLVLSDVNDNAPIPEPRNMQFCQRNPKPHVITILDPDLPP
>sp|erin-1 ghsfdshkd OX=10116 GN=Cdh1 PE=1 SV=1|sp|P22223|CADH3_HUMAN Cadherin-3 OX=9606 GN=CDH3 PE=1 SV=2
ESYPTYTLVVQAADLQGEGLSTTAKAVITVKDINDNAPIFNPSTYLQCAASEPCRAVFREAEVTLEAGGAEQEPGQALGKVFMGCPGQEPALFSTD
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3
MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH
I want to keep only those records where there are two matches of OX values,hence,the desired output should like the following :
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|OX=10116 GN=Cdh3 PE=4 SV=3
MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH
The code I have tried is following :
awk -v p="OX=" 'FNR==1{x=0}{x+=gsub(p,p);if(x>2){print $line}}' test.fasta
回答1:
I came up with this awk
script, which seems to work.
awk '
printnext == 1 { #Prints the line after the line w 2 matches
print;
printnext=0;
}
match($0, /OX=[0-9]*/) { #Looks for OX=numbers
id=substr($0,RSTART,RLENGTH); #Saves it to id
c=0;
for (i=1;i<=NF;i++){ #Looks for two occurrences of id in line
if ($i==id){
c=c+1;
if (c==2) {print;printnext=1}
}
}
}
' test.fasta
回答2:
How about this one, without using loop. Could you please try following. Will add detailed explanation in few mins.
awk '
match($0,/OX=[0-9]+/){
val=substr($0,RSTART,RLENGTH)
if(gsub(val,"&")==2){
print
found=1
}
val=""
next
}
found{
found=""
print
}
' Input_file
OR a small editing in above solution where remove val=""
part as per @Quasimodo comment:
awk '
match($0,/OX=[0-9]+/){
val=substr($0,RSTART,RLENGTH)
if(gsub(val,"&")==2){
print
found=1
}
next
}
found{
found=""
print
}
' Input_file
Explanation: Adding a detailed explanation for above code.
awk ' ##Starting awk program from here.
match($0,/OX=[0-9]+/){ ##Using match function to match OX= digits in current line.
val=substr($0,RSTART,RLENGTH) ##Creating variable val whose value is sub-string of value of current line starts from RSTART till value of RLENGTH.
if(gsub(val,"&")==2){ ##Checking condition if value of Global substitutions is equal to 2 then do following.
print ##Printing the current line.
found=1 ##Setting variable found value as 1 here.
}
val="" ##Nullifying variable val here.
next ##next will skip all further statements from here.
}
found{ ##Checking condition if variable found is NOT NULL then do following.
found="" ##Nullifying variable found here.
print ##Printing current line here.
}
' Input_file ##Mentioning Input_file name here.
EDIT: NOTE, this code is trying to cover an edge case if anyone's samples are exact same as shown by OP then above codes should be Good enough.
Trying to cover an edge case here mentioned by @kvantour in comments, changed regex a bit where it checks like OX
should be preceded and followed by a space.
awk '
match($0,/\s+OX=[0-9]+\s+/){
val=substr($0,RSTART,RLENGTH)
if(gsub(val,"&")==2){
print
found=1
}
val=""
next
}
found{
found=""
print
}
' Input_file
回答3:
With GNU awk, you can use patsplit and split by desired content vs by some delimiter.
Given:
$ cat test.fasta
>sp|rin-1 ghsfdhjkuesl OX=10116 GN=Cdh1 PE=1 SV=1|sp|P10287|ghsfdjdeosd gdhkhs OX=10090 GN=Cdh3 PE=1 SV=2
WRDTANWLEINPETGVISTRAEMDREDSEHVKNSTYTALIIATDDGSPIATGTGTLLLVLSDVNDNAPIPEPRNMQFCQRNPKPHVITILDPDLPP
>sp|erin-1 ghsfdshkd OX=10116 GN=Cdh1 PE=1 SV=1|sp|P22223|CADH3_HUMAN Cadherin-3 OX=9606 GN=CDH3 PE=1 SV=2
ESYPTYTLVVQAADLQGEGLSTTAKAVITVKDINDNAPIFNPSTYLQCAASEPCRAVFREAEVTLEAGGAEQEPGQALGKVFMGCPGQEPALFSTD
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3
MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH
You can split and capture by value pairs, in this case by OX=
:
$ awk -v RS=$'>' '{
cnt=patsplit($0, arr, "OX=[0-9]+")
if (cnt==2 && arr[1]==arr[2])
printf ">%s", $0
}' test.fasta
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3
MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH
回答4:
awk -F'[O][X][=]' '{a=$0; gsub(/ .*/,"",$2) ; gsub(/ .*/,"",$3) ; if ($2==$3) print a }'
Demo
:>cat regular_expressions_are_greedy.txt
>sp|rin-1 ghsfdhjkuesl OX=10116 GN=Cdh1 PE=1 SV=1|sp|P10287|ghsfdjdeosd gdhkhs OX=10090 GN=Cdh3 PE=1 SV=2WRDTANWLEINPETGVISTRAEMDREDSEHVKNSTYTALIIATDDGSPIATGTGTLLLVLSDVNDNAPIPEPRNMQFCQRNPKPHVITILDPDLPP
>sp|erin-1 ghsfdshkd OX=10116 GN=Cdh1 PE=1 SV=1|sp|P22223|CADH3_HUMAN Cadherin-3 OX=9606 GN=CDH3 PE=1 SV=2ESYPTYTLVVQAADLQGEGLSTTAKAVITVKDINDNAPIFNPSTYLQCAASEPCRAVFREAEVTLEAGGAEQEPGQALGKVFMGCPGQEPALFSTD
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH
:>awk -F'[O][X][=]' '{a=$0; gsub(/ .*/,"",$2) ; gsub(/ .*/,"",$3) ; if ($2==$3) print a }' regular_expressions_are_greedy.txt
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH
:>
Explanation:
awk -F'[O][X][=]' <--- Setting field separator as "OX="
'{
a=$0; <-- Saving input record in variable a. ($0 = Means whole records)
gsub(/ .*/,"",$2) ; <-- Removing all character after space from column 1
gsub(/ .*/,"",$3) ; <-- Removing all character after space from column 2
if ($2==$3) <-- Checking if 2 values are equal.
print a
}'
回答5:
A very quick way would be to do something like this:
awk '/^>/{p=0;delete a
for(i=1;i<=NF;++i) a[$i]++
for(i in a) if (i ~ /^OX=/ && a[i]>1) p=1
}
p' file
This will match cases such as:
> foobar OX=1 OX=2 OX=3 OX=1
ABCDEF
A bit more optimized if you care only about the string OX=
, you can do:
awk '/^>/{p=0;delete a
for(i=1;i<=NF;++i) if($i ~ /^OX=/) a[$i]++
for(i in a) if (a[i]>1) p=1
}
p' file
来源:https://stackoverflow.com/questions/60497313/keep-fasta-records-which-have-2-matches-of-ox-values