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