<p>It seems like you want to do four things:</p>

<ol>
<li>Remove all text up to and including the first <code>|</code>.</li>
<li>Now that that has been removed, take the string between what is now (after step 1) the first <code>|</code> and what is now the second <code>|</code>, and append it to the end of the header with a <code>_</code>. </li>
<li>Replace all <code>__</code> with <code>:</code> and all <code>;</code> with <code>,</code>.</li>
<li>Change the (fixed?) string <code>reps|k</code> with <code>tax=d</code>.</li>
</ol>

<p>If so, and assuming that you only have one occurrence of <code>reps|</code> in each header, you can do:</p>

<pre><code>$ sed 's/&gt;[^|]*|/&gt;/; 
       s/reps|k/tax=d/; 
       s/__/:/g; 
       s/;/,/g; 
       s/|\([^|]*\)\(|.*\)/|\1\2_\1;/; ' file.fa 
&gt;JF514531|SH174817.07FU;tax=d:Fungi,p:Basidiomycota,c:Agaricomycetes,o:Agaricales,f:Agaricaceae,g:Agaricus,s:Agaricus_chiangmaiensis_SH174817.07FU;
</code></pre>

<p>This will:</p>

<ul>
<li><code>s/&gt;[^|]*|/&gt;/</code> : replace the longest stretch of non<code>-|</code> characters after a <code>&gt;</code> and until the first <code>|</code> with <code>&gt;</code> alone.</li>
<li><code>s/reps|k/tax=d/;</code> : replace the first occurrence of the string <code>reps|k</code> with <code>tax=</code>.</li>
<li><code>s/__/:/g; s/;/,/g</code> : replace <em>all</em> (that's what the <code>/g</code> means) occurrences of <code>__</code> with <code>:</code> and of <code>;</code> with <code>,</code>.</li>
<li><p><code>s/|\([^|]*\)\(|.*\)/|\1\2_\1;/</code> : the <code>\(foo\)</code> construct is called a <a href="https://www.regular-expressions.info/brackets.html" rel="nofollow noreferrer">capturing group</a> and will <em>capture</em> <code>foo</code> and save it as <code>\1</code>, which can be used on the right hand side of the replacement operator. The next captured group will be <code>\2</code> then <code>\3</code> etc. Here, with <code>|\([^|]*\)</code> we are capturing the longest string of non<code>|</code> found after the 1st <code>|</code> (this happens after the first operation, so the 1st <code>|</code> is the one that was 3rd in the original) and then everything after the next <code>|</code> (<code>|.*</code>) until the end of the line. We then replace everything matched with a <code>|</code>, then whatever was matched by the first capture group (<code>\1</code>), then the second (<code>\2</code>), then we add a <code>_</code> and repeat the <code>\1</code>. 
Finally, if you want to make the changes to the original input file, use <code>-i</code>:</p>

<pre><code>sed -i.bak 's/&gt;[^|]*|/&gt;/; s/reps|k/tax=d/; s/__/:/g; s/;/,/g; s/|\([^|]*\)\(|.*\)/|\1\2_\1;/; ' file.fa
</code></pre>

<p>That will save the original file as <code>file.fa.bak</code>. use <code>-i</code> alone without any argument if you don't need the backup. </p></li>
</ul>

CC BY-SA 4.0
2019-01-22T18:27:12.470Z
This works really well, except for two things:  the command changes reps to tax for every other header, and there is still a | in front of tax instead of ;.
Graham
CC BY-SA 4.0
2019-01-19T13:20:05.290Z
2019-01-22T17:37:23.440Z
2019-01-22T17:37:23.440Z
terdon
<p>If <code>awk</code> is good as well:</p>

<pre><code><span class="math-container">$ awk -v FS="|" -v OFS="|" '/&gt;/{
    gsub(";",",", $5); 
    gsub("__",":",$5); 
    print "&gt;"$2,$3";tax="$5"_"$</span>3";";
    next;
}1' file.fa
&gt;JF514531|SH174817.07FU;tax=k:Fungi,p:Basidiomycota,c:Agaricomycetes,o:Agaricales,f:Agaricaceae,g:Agaricus,s:Agaricus_chiangmaiensis_SH174817.07FU;
</code></pre>

<p>This relies on the order of the parts separated by <code>|</code>.</p>

<p>I don't understand why <code>k__Fungi</code> becomes <code>d:Fungi</code>, so I ignored it for now. </p>

<p>Some explanation for what <code>awk</code>is doing.</p>

<ul>
<li><code>|</code> is defined as a field (column) separator for the input and output</li>
<li>If the line contains a <code>&gt;</code> the code between <code>{</code> and <code>}</code> is executed.</li>
<li>the first <code>gsub</code> replaces <code>;</code> with <code>,</code> in the 5th field</li>
<li>the second <code>gsub</code> replaces <code>__</code> with <code>:</code> in the 5th field</li>
<li>then we print the new header line. The <code><span class="math-container">$2</code>, <code>$</span>3</code> and <code><span class="math-container">$5</code> get replaced by the values of the second, third and 5th field of the input. <code>,</code> get replaced by the defined output field separator</li>
<li>with <code>next</code> we tell <code>awk</code> to go to the next input line and repeat the code</li>
<li>The <code>1</code> is in equivalent to <code>print $</span>0</code> for printing the whole input line. In our code this is only executed if the line is no header line. </li>
</ul>

CC BY-SA 4.0
2019-01-22T11:48:04.393Z
I don't know awk that well. However, I find this is a really nice example and it makes me want to learn more awk!
winni2k
CC BY-SA 4.0
2019-01-22T17:40:38.123Z
Note that this won't print the sequences, only the header.
terdon
CC BY-SA 4.0
2019-01-22T18:32:20.567Z
I just noticed this - how would you change this?
Graham
CC BY-SA 4.0
2019-01-22T18:55:14.263Z
I edited my answer.
finswimmer
CC BY-SA 4.0
2019-01-19T08:09:15.683Z
2019-01-22T19:20:40.970Z
2019-01-22T19:20:40.970Z
finswimmer
<p>I appologize for asking this, but I really am really bad with regex...</p>

<p>Can someone help me transform the headers of my fasta files from this:</p>

<pre><code>&gt;Agaricus_chiangmaiensis|JF514531|SH174817.07FU|reps|k__Fungi;p__Basidiomycota;c__Agaricomycetes;o__Agaricales;f__Agaricaceae;g__Agaricus;s__Agaricus_chiangmaiensis
</code></pre>

<p>to this:</p>

<pre><code>&gt;JF514531|SH174817.07FU;tax=d:Fungi,p:Basidiomycota,c:Agaricomycetes,o:Agaricales,f:Agaricaceae,g:Agaricus,s:Agaricus_chiangmaiensis_SH174817.07FU;
</code></pre>

<p>seems like I could use the command </p>

<pre><code>sed 's/__/:/g;s/;/,/g;s/.*|/|/g' 
</code></pre>

<p>to substitute <code>:</code> for <code>__</code>, and <code>,</code> for <code>;</code>.  I'm not entirely sure how to proceed from there though...</p>

<p>Thank you</p>

CC BY-SA 4.0
2019-01-19T13:11:52.027Z
Could you [edit] your question and explain the transformation you need please? You don't only want to replace `__` with `:` and `;` with `,`. You also seem to be removing some text. Do you always want to remove whatever is before the first `|`? And what happened to the `reps`? And why is `k__Fungi` becoming `tax=d:Fungi` instead of `k:Fungi`? We need to know exactly what you are trying to do in order to give an answer that works for you.
terdon
CC BY-SA 4.0
2019-01-22T17:35:25.583Z
Looks like you figured it out without more clarification - I'll try to be more concise when asking in the future -
Graham
<fasta><text-processing>
How do I re-name the headers of my Fasta file?
# How do I re-name the headers of my Fasta file?

(Asked by: username_0 on 2019-01-19)

I appologize for asking this, but I really am really bad with regex...
Can someone help me transform the headers of my fasta files from this:
>Agaricus_chiangmaiensis|JF514531|SH174817.07FU|reps|k__Fungi;p__Basidiomycota;c__Agaricomycetes;o__Agaricales;f__Agaricaceae;g__Agaricus;s__Agaricus_chiangmaiensis

to this:
>JF514531|SH174817.07FU;tax=d:Fungi,p:Basidiomycota,c:Agaricomycetes,o:Agaricales,f:Agaricaceae,g:Agaricus,s:Agaricus_chiangmaiensis_SH174817.07FU;

seems like I could use the command 
sed 's/__/:/g;s/;/,/g;s/.*|/|/g' 

to substitute : for __, and , for ;.  I'm not entirely sure how to proceed from there though...
Thank you

**Tags:** fasta, text-processing
> **Comments:**
> **username_1**: Could you [edit] your question and explain the transformation you need please? You don't only want to replace `__` with `:` and `;` with `,`. You also seem to be removing some text. Do you always want to remove whatever is before the first `|`? And what happened to the `reps`? And why is `k__Fungi` becoming `tax=d:Fungi` instead of `k:Fungi`? We need to know exactly what you are trying to do in order to give an answer that works for you.  
> **username_0**: Looks like you figured it out without more clarification - I'll try to be more concise when asking in the future -  

---

## 2 answers

### Answer by username_2 on 2019-01-19. Score: 5 | Accepted answer

If awk is good as well:
$ awk -v FS="|" -v OFS="|" '/>/{
    gsub(";",",", $5); 
    gsub("__",":",$5); 
    print ">"$2,$3";tax="$5"_"$3";";
    next;
}1' file.fa
>JF514531|SH174817.07FU;tax=k:Fungi,p:Basidiomycota,c:Agaricomycetes,o:Agaricales,f:Agaricaceae,g:Agaricus,s:Agaricus_chiangmaiensis_SH174817.07FU;

This relies on the order of the parts separated by |.
I don't understand why k__Fungi becomes d:Fungi, so I ignored it for now. 
Some explanation for what awkis doing.

| is defined as a field (column) separator for the input and output
If the line contains a > the code between { and } is executed.
the first gsub replaces ; with , in the 5th field
the second gsub replaces __ with : in the 5th field
then we print the new header line. The $2, $3 and $5 get replaced by the values of the second, third and 5th field of the input. , get replaced by the defined output field separator
with next we tell awk to go to the next input line and repeat the code
The 1 is in equivalent to print $0 for printing the whole input line. In our code this is only executed if the line is no header line.

> **Comments:**
> **username_3**: I don't know awk that well. However, I find this is a really nice example and it makes me want to learn more awk!  
> **username_1**: Note that this won't print the sequences, only the header.  
> **username_0**: I just noticed this - how would you change this?  
> **username_2**: I edited my answer.  

---

### Answer by username_1 on 2019-01-19. Score: 3

It seems like you want to do four things:

Remove all text up to and including the first |.
Now that that has been removed, take the string between what is now (after step 1) the first | and what is now the second |, and append it to the end of the header with a _. 
Replace all __ with : and all ; with ,.
Change the (fixed?) string reps|k with tax=d.

If so, and assuming that you only have one occurrence of reps| in each header, you can do:
$ sed 's/>[^|]*|/>/; 
       s/reps|k/tax=d/; 
       s/__/:/g; 
       s/;/,/g; 
       s/|\([^|]*\)\(|.*\)/|\1\2_\1;/; ' file.fa 
>JF514531|SH174817.07FU;tax=d:Fungi,p:Basidiomycota,c:Agaricomycetes,o:Agaricales,f:Agaricaceae,g:Agaricus,s:Agaricus_chiangmaiensis_SH174817.07FU;

This will:

s/>[^|]*|/>/ : replace the longest stretch of non-| characters after a > and until the first | with > alone.
s/reps|k/tax=d/; : replace the first occurrence of the string reps|k with tax=.
s/__/:/g; s/;/,/g : replace all (that's what the /g means) occurrences of __ with : and of ; with ,.
s/|\([^|]*\)\(|.*\)/|\1\2_\1;/ : the \(foo\) construct is called a capturing group and will capture foo and save it as \1, which can be used on the right hand side of the replacement operator. The next captured group will be \2 then \3 etc. Here, with |\([^|]*\) we are capturing the longest string of non| found after the 1st | (this happens after the first operation, so the 1st | is the one that was 3rd in the original) and then everything after the next | (|.*) until the end of the line. We then replace everything matched with a |, then whatever was matched by the first capture group (\1), then the second (\2), then we add a _ and repeat the \1. 
Finally, if you want to make the changes to the original input file, use -i:
sed -i.bak 's/>[^|]*|/>/; s/reps|k/tax=d/; s/__/:/g; s/;/,/g; s/|\([^|]*\)\(|.*\)/|\1\2_\1;/; ' file.fa

That will save the original file as file.fa.bak. use -i alone without any argument if you don't need the backup.

> **Comments:**
> **username_0**: This works really well, except for two things:  the command changes reps to tax for every other header, and there is still a | in front of tax instead of ;.  

---

