<p>You were so close! This should do the trick:</p>

<pre><code>for i in {314..727}; do 
    sed -i.bak "s/^&gt;/&gt;<span class="math-container">${i}_/" mgm4761$</span>{i}.3/*.fna
done
</code></pre>

<p>Note that I am using <code>-i</code> which makes <code>sed</code> edit the original file. Because I use <code>-i.bak</code>, this will create a backup file with the original data. Once you are sure the command does what you need, you can delete all of these files with <code>rm */*fna.bak</code>.</p>

CC BY-SA 4.0
2019-09-26T16:21:17.560Z
This seems to be a step in the right direction! However, there's something about it which went weird. It does what it's supposed to, but it also duplicates the headers. Example: '>314_NS500799:83:H53J2AFXX:2:11101:11350:1048
>314_NS500799:83:H53J2AFXX:2:11101:11350:1048
GGGCAGTCCTTGCAGGGTGATACAGTCACCGTTTCTCTGAATGGGGAGGATCGTCCCCAAACTGTCAAGTACTACCGTTTGGCCCAGATCGTCTTTCAGAACCCGTACTCTTCACTGAATCCGCGCAAGCCGGTGCGCGACATCGTCGGCA
>314_NS500799:83:H53J2AFXX:2:11101:2772:1050
>314_NS500799:83:H53J2AFXX:2:11101:2772:1050
etc'
Laura
CC BY-SA 4.0
2019-09-26T16:31:16.147Z
IMO perl -p -i -e gives you more regex power, but this problem is easily solved just anchor the match and delete to the end
M__
CC BY-SA 4.0
2019-09-26T16:57:44.063Z
@Laura argh! That's because I'm an idiot and left a debugging command I had used while testing my answer. If you've run it already, you will want to rename all the `bak` files back to the original. You can do this with: `for i in */*bak; do mv "$i" "${i//.bak}"; done`. Then, run the updated command (without the `p` at the end of the `s///`) and it should work as expected.
terdon
CC BY-SA 4.0
2019-09-26T16:59:03.363Z
@MichaelG. yes, `perl` is indeed better (and is where `sed` got the `-i` from), but overkill here. The match is already anchored to the beginning. The issue was that I had used `s/foo/bar/p` and the `p` causes `sed` to print any line where the substitution was successful. I was using that along with `-n` which suppresses output to test that it was working as expected, but forgot to remove it when posting the answer.
terdon
CC BY-SA 4.0
2019-09-26T17:03:01.677Z
@Laura if you didn't keep the backup files, you can remove the duplicated headers with `perl -i -ne 'if(/^>/ && $_ eq $last){next}; print; $last=$_; ' */*fna`.
terdon
CC BY-SA 4.0
2019-10-01T13:49:00.167Z
@MichaelG. Do you know, by any chance, how I could add a layer of complexity to this code? As in, instead of adding from a range of numbers that happen to be equivalent to folder endings, would there be a way to do this if I didn't know those numbers from before? I tried this to add codes from multiple folder names to the fasta, but...it's so bad that I'm not even getting an error message.
`for j in ${j}; do
        for i in ${i}; do
                sed -i.bak "s/^>/>${j}_${i}_/" mgp${j}/mgm????${i}.3/*.fna
        done
done`
Laura
CC BY-SA 4.0
2019-10-01T15:52:25.233Z
@terdon is the expert on bash and awk. Personally I'd write a Perl script using glob, you might achieve it by piping.
M__
CC BY-SA 4.0
2019-10-01T16:03:48.903Z
Looking at your code, that is  alot  of directories why not replace ??? With *
M__
CC BY-SA 4.0
2019-10-01T16:47:34.060Z
@Laura I'm afraid I can't answer without knowing your directory names. But as Micahel said, `for dir in *` might be enough. You might want to ask a new question though where you can give us the relevant details (the devil's in the details with this sort of thing).
terdon
CC BY-SA 4.0
2019-09-26T16:01:04.813Z
2019-09-26T16:57:49.220Z
2019-09-26T16:57:49.220Z
terdon
<p>My directories are organized as follows: one main directory, in which I have multiple directories that end with a number ranging from 314 to 727, followed by .3   . For example, 'mgm4761314.3'. Within these directories, I have fasta files named after a similar pattern (for example, mgm4761314.3.299.screen.passed.fna is in the directory mgm4761314.3).</p>

<p>There is only one such file (.fna) per directory.</p>

<p>What I've been trying to do is to write a loop that would go through all these folders and fasta files, and add the short number associated with the folder/file name (eg. 314, 315...727) to the headers. For example, for my first folder/fasta file, instead of:</p>

<pre><code>&gt;seq1
&gt;seq2
</code></pre>

<p>I want:</p>

<pre><code>&gt;314_seq1
&gt;314_seq2
</code></pre>

<p>The output would be exported to a file called, for instance, 314.fna.</p>

<p>I've sort of made it work for one number at a time, but I have plenty of files, so I'd appreciate if anyone could help me with the loop part! This is what I tried (and it didn't work). Using ubuntu.</p>

<pre><code>for i in {314..727}; do sed "s/&gt;/&gt;<span class="math-container">${i}_/" [...]/*$</span>{i}.3/mgm4761<span class="math-container">${i}.3.299.screen.passed.fna &gt; [...]/*$</span>{i}.3/${i}.fna; done
</code></pre>

CC BY-SA 4.0
2019-09-26T15:37:48.693Z
This should be easy enough, but please [edit] your question to clarify the directory structure. Does this need to be done to _all_ files with an `.fna` extension in each directory?
terdon
CC BY-SA 4.0
2019-09-26T15:46:13.733Z
@terdon Edited! Basically, there is only one file per directory (and all files are .fna)
Laura
CC BY-SA 4.0
2019-09-26T16:29:30.517Z
Or could go perl -p -i -e 's/
M__
<fasta><bash>
How to edit the headers of multiple fasta files from multiple folders?
# How to edit the headers of multiple fasta files from multiple folders?

(Asked by: username_0 on 2019-09-26)

My directories are organized as follows: one main directory, in which I have multiple directories that end with a number ranging from 314 to 727, followed by .3   . For example, 'mgm4761314.3'. Within these directories, I have fasta files named after a similar pattern (for example, mgm4761314.3.299.screen.passed.fna is in the directory mgm4761314.3).
There is only one such file (.fna) per directory.
What I've been trying to do is to write a loop that would go through all these folders and fasta files, and add the short number associated with the folder/file name (eg. 314, 315...727) to the headers. For example, for my first folder/fasta file, instead of:
>seq1
>seq2

I want:
>314_seq1
>314_seq2

The output would be exported to a file called, for instance, 314.fna.
I've sort of made it work for one number at a time, but I have plenty of files, so I'd appreciate if anyone could help me with the loop part! This is what I tried (and it didn't work). Using ubuntu.
for i in {314..727}; do sed "s/>/>${i}_/" [...]/*${i}.3/mgm4761${i}.3.299.screen.passed.fna > [...]/*${i}.3/${i}.fna; done

**Tags:** fasta, bash
> **Comments:**
> **username_1**: This should be easy enough, but please [edit] your question to clarify the directory structure. Does this need to be done to _all_ files with an `.fna` extension in each directory?  
> **username_0**: @terdon Edited! Basically, there is only one file per directory (and all files are .fna)  
> **username_2**: Or could go perl -p -i -e 's/  

---

## 1 answers

### Answer by username_1 on 2019-09-26. Score: 3 | Accepted answer

You were so close! This should do the trick:
for i in {314..727}; do 
    sed -i.bak "s/^>/>${i}_/" mgm4761${i}.3/*.fna
done

Note that I am using -i which makes sed edit the original file. Because I use -i.bak, this will create a backup file with the original data. Once you are sure the command does what you need, you can delete all of these files with rm */*fna.bak.

> **Comments:**
> **username_0**: This seems to be a step in the right direction! However, there's something about it which went weird. It does what it's supposed to, but it also duplicates the headers. Example: '>314_NS500799:83:H53J2AFXX:2:11101:11350:1048 >314_NS500799:83:H53J2AFXX:2:11101:11350:1048 GGGCAGTCCTTGCAGGGTGATACAGTCACCGTTTCTCTGAATGGGGAGGATCGTCCCCAAACTGTCAAGTACTACCGTTTGGCCCAGATCGTCTTTCAGAACCCGTACTCTTCACTGAATCCGCGCAAGCCGGTGCGCGACATCGTCGGCA >314_NS500799:83:H53J2AFXX:2:11101:2772:1050 >314_NS500799:83:H53J2AFXX:2:11101:2772:1050 etc'  
> **username_2**: IMO perl -p -i -e gives you more regex power, but this problem is easily solved just anchor the match and delete to the end  
> **username_1**: @Laura argh! That's because I'm an idiot and left a debugging command I had used while testing my answer. If you've run it already, you will want to rename all the `bak` files back to the original. You can do this with: `for i in */*bak; do mv "$i" "${i//.bak}"; done`. Then, run the updated command (without the `p` at the end of the `s///`) and it should work as expected.  
> **username_1**: @MichaelG. yes, `perl` is indeed better (and is where `sed` got the `-i` from), but overkill here. The match is already anchored to the beginning. The issue was that I had used `s/foo/bar/p` and the `p` causes `sed` to print any line where the substitution was successful. I was using that along with `-n` which suppresses output to test that it was working as expected, but forgot to remove it when posting the answer.  
> **username_1**: @Laura if you didn't keep the backup files, you can remove the duplicated headers with `perl -i -ne 'if(/^>/ && $_ eq $last){next}; print; $last=$_; ' */*fna`.  
> **username_0**: @MichaelG. Do you know, by any chance, how I could add a layer of complexity to this code? As in, instead of adding from a range of numbers that happen to be equivalent to folder endings, would there be a way to do this if I didn't know those numbers from before? I tried this to add codes from multiple folder names to the fasta, but...it's so bad that I'm not even getting an error message. `for j in ${j}; do         for i in ${i}; do                 sed -i.bak "s/^>/>${j}_${i}_/" mgp${j}/mgm????${i}.3/*.fna         done done`  
> **username_2**: @terdon is the expert on bash and awk. Personally I'd write a Perl script using glob, you might achieve it by piping.  
> **username_2**: Looking at your code, that is  alot  of directories why not replace ??? With *  
> **username_1**: @Laura I'm afraid I can't answer without knowing your directory names. But as Micahel said, `for dir in *` might be enough. You might want to ask a new question though where you can give us the relevant details (the devil's in the details with this sort of thing).  

---

