Home > Software engineering >  How to stop bash loop from looping over files created during the loop?
How to stop bash loop from looping over files created during the loop?

Time:09-30

I want to run a loop over all files of a particular extension in a directory:

for i in *.bam
do
...
done

However, if the command that I run inside the loop creates a temporary file of the same extension, the loop tries to process this new tmp file as well. This is unwanted. So, I thought the following would solve the problem: first list all the *.bam files in the directory, save that list to a variable, and then loop over this saved list:

list_bam=$(for i in *.bam; do echo $i; done)

for i in $list_bam
do
...
done

To my surprise, this runs into the same problem! Could someone please explain the logic behind this and how to fix it so that the loop only processes the pre-existing .bam files?

CodePudding user response:

Instead of a loop you can use find and xargs

find . -maxdepth 1 -type f -name "*.bam" -print0 | \
   xargs -0 -I{} bash -c 'echo "{}" > "{}.new.bam"'

or

find . -maxdepth 1 -type f -name "*.bam" -print0 | \
   xargs -0 -I{} bash -c 'echo "$1" > "$1.new.bam"' -- {}

example:

$ touch a.bam b.bam
$ ls 
a.bam  b.bam
$ find . -maxdepth 1 -type f -name "*.bam" -print0 | \
    xargs -0 -I{} bash -c 'echo "{}" > "{}.new.bam"' 
$ ls
a.bam  a.bam.new.bam  b.bam  b.bam.new.bam

CodePudding user response:

You should perhaps make sure that your globbing expression *.bam couldn't be interpreted afterward with something like:

list_bam=$(ls *.bam)

...

...but, as noticed by @glenn in the comments, this is a bad idea. Something similar should be made using a find ... -print0 | xargs -0 ... command template.

  • Related