1
$\begingroup$

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?

$\endgroup$
2
  • 2
    $\begingroup$ Is there fasta sequence between the headers? If so is it multiline or single line fasta? Also what about Biopython? $\endgroup$
    – M__
    May 24, 2020 at 20:16
  • $\begingroup$ 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 $\endgroup$
    – taeju
    May 25, 2020 at 12:42

4 Answers 4

6
$\begingroup$
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 >.

$\endgroup$
1
  • $\begingroup$ 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 $\endgroup$
    – taeju
    May 25, 2020 at 12:51
8
$\begingroup$
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.
$\endgroup$
1
  • $\begingroup$ 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. $\endgroup$
    – taeju
    May 25, 2020 at 12:49
3
$\begingroup$

sed -E 's/>(.+)::(.+)/>\2_\1/' in.fa > out.fa

If you want to use sed.

$\endgroup$
2
  • 1
    $\begingroup$ This misses the > at the beginning of each name: sed -r 's/>(.+)::(.+)/>\2_\1/' for linux and sed -E 's/>(.+)::(.+)/>\2_\1/' for macOS. $\endgroup$
    – user3051
    May 25, 2020 at 12:55
  • 1
    $\begingroup$ Sorry there was a little typo. Now it should work properly $\endgroup$
    – Mr_Z
    May 25, 2020 at 13:00
2
$\begingroup$

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
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.