# Edit FASTA header using sed

I need to rename the following headers from a FASTA file. Something like:

>ENST00000488147.1::chr1:29570-30013(-)
>ENST00000405392.5::chr2:24919186-24920186(-)


into different format like this:

>chr1:29570-30013(-)_ENST00000488147.1
>chr2:24919186-24920186(-)_ENST00000405392.5


How can I rename the FASTA headers, perhaps using sed or awk?

• Is there fasta sequence between the headers? If so is it multiline or single line fasta? Also what about Biopython?
– M__
May 24 '20 at 20:16
• Hi Michael. Yes, there are fasta sequences between the headers, and it has a large number of fasta sequences alongside their headers for each. I didn't know anything about Biopython, but I just looked it up and it seems really helpful as it has motif analysis tools (MEME or MAST). Thank you May 25 '20 at 12:42

## 4 Answers

awk -F "::" '{if($$1~">"){gsub(">","");print ">"2"_"1} else {print$$0}}' foo.fa


Basically the same as from Devon but using -F to indicate the initial field delimiter and then using gsub to remove the >.

• Hello ATpoint. Thank you for your answer. I should've used gsub instead of sed to remove the string that I don't want. Thank you for your answer May 25 '20 at 12:51
awk 'BEGIN{FS="::"}{if($$1~">"){printf(">%s_%s\n",2,substr(1,2))}else{print$$0}}' input_file.fa > output.fa


An explanation of the non-obvious bits:

• BEGIN{FS="::"} split columns using :: as the designator
• $1~">" If there's a > in the line • substr($1,2) Trim the > that was at the beginning of the line.
• awk -F:: '{sub(/>/, ">" $2 "_"); print}' KDM4A_1kbp_TSS.fasta > KDM4A_1kbp_TSS_swp.fasta sed 's/::chr.*)//' KDM4A_1kbp_TSS_swp.fasta > KDM4A_1kbp_TSS_MEMEinput.fasta I just checked your answer now. I had tried working by myself and come up with this script. But, yours looks much better than mine :) I appreciate it for your answer. May 25 '20 at 12:49 sed -E 's/>(.+)::(.+)/>\2_\1/' in.fa > out.fa If you want to use sed. • This misses the > at the beginning of each name: sed -r 's/>(.+)::(.+)/>\2_\1/' for linux and sed -E 's/>(.+)::(.+)/>\2_\1/' for macOS. May 25 '20 at 12:55 • Sorry there was a little typo. Now it should work properly – Mr_Z May 25 '20 at 13:00 I would use perl here instead of sed so you can use non-greedy patterns (e.g. .*?) and so ensure that you always match the first occurrence of :: if there are more than one on the line. Perl also has -i, and in fact is where sed got the idea from, so you can edit the file in place just like you can with sed. Using this example file: $ cat file.fa
>ENST00000488147.1::chr1:29570-30013(-)
ACCTCTGAGAGCACCTCTGAGAGCACCTCTGAGAGCACCTCTGAGAGC
ATATATCGGCATATATCGGCATATATCGGCATATATCGGCATATATCG
>ENST00000405392.5::chr2:24919186-24920186(-)
ACTCTAGGATATCGCGATATCGCCTTAGGCTAGAATCGGCTTAGC
TCGCGATATCATCGCCTTAGGCTAGAATCGTCTAGGATATCGCG
CCTTAGGCTATCATCGCCTAGAATCGTCTAGGATATCGAATC


You can do:

$$perl -pe 's/>(.+?)::(.*)/>$$2_$1/' file.fa >chr1:29570-30013(-)_ENST00000488147.1 ACCTCTGAGAGCACCTCTGAGAGCACCTCTGAGAGCACCTCTGAGAGC ATATATCGGCATATATCGGCATATATCGGCATATATCGGCATATATCG >chr2:24919186-24920186(-)_ENST00000405392.5 ACTCTAGGATATCGCGATATCGCCTTAGGCTAGAATCGGCTTAGC TCGCGATATCATCGCCTTAGGCTAGAATCGTCTAGGATATCGCG CCTTAGGCTATCATCGCCTAGAATCGTCTAGGATATCGAATC  Or, to edit the file in place: $$perl -i -pe 's/>(.+?)::(.*)/>$$2_$$1/' file.fa$$ cat file.fa >chr1:29570-30013(-)_ENST00000488147.1 ACCTCTGAGAGCACCTCTGAGAGCACCTCTGAGAGCACCTCTGAGAGC ATATATCGGCATATATCGGCATATATCGGCATATATCGGCATATATCG >chr2:24919186-24920186(-)_ENST00000405392.5 ACTCTAGGATATCGCGATATCGCCTTAGGCTAGAATCGGCTTAGC TCGCGATATCATCGCCTTAGGCTAGAATCGTCTAGGATATCGCG CCTTAGGCTATCATCGCCTAGAATCGTCTAGGATATCGAATC  ### Explanation • perl -pe: print each line of the input file after applying the script given by -e to it. • s/>(.+?)::(.*)/>$2_$1/': the s/old/new/ is the substitution operator and will replace old with new. Here, we look for the shortest stretch of one or more characters (.+?) from the > until the first occurrence of ::, and capture it as $1 (because the pattern is in parentheses). Everything after the first :: is then captured as $2 ((.*)). Then, we replace everything we matched with a >, then the 2nd captured pattern, an underscore and the first captured pattern. Just for fun, here's a golfed awk approach: $$awk -F'::' '$$0=sub(/>/,"")?">"$$2"_"$$1:$0' file.fa
>chr1:29570-30013(-)_ENST00000488147.1
ACCTCTGAGAGCACCTCTGAGAGCACCTCTGAGAGCACCTCTGAGAGC
ATATATCGGCATATATCGGCATATATCGGCATATATCGGCATATATCG
>chr2:24919186-24920186(-)_ENST00000405392.5
ACTCTAGGATATCGCGATATCGCCTTAGGCTAGAATCGGCTTAGC
TCGCGATATCATCGCCTTAGGCTAGAATCGTCTAGGATATCGCG
CCTTAGGCTATCATCGCCTAGAATCGTCTAGGATATCGAATC