#bash #loops
Вопрос:
Я хочу запустить цикл по всем файлам определенного расширения в каталоге:
for i in *.bam
do
...
done
Однако, если команда, которую я выполняю внутри цикла, создает временный файл с тем же расширением, цикл также пытается обработать этот новый файл tmp. Это нежелательно. Итак, я подумал, что проблема решится следующим образом: сначала перечислите все файлы *.bam в каталоге, сохраните этот список в переменной, а затем выполните цикл по этому сохраненному списку:
list_bam=$(for i in *.bam; do echo $i; done)
for i in $list_bam
do
...
done
К моему удивлению, это сталкивается с той же проблемой! Не мог бы кто-нибудь, пожалуйста, объяснить логику этого и как это исправить, чтобы цикл обрабатывал только существующие файлы .bam?
Комментарии:
1.
echo $list_bam
не дает списка. Это просто дает*.bam
. Вероятно, вам придется сохранить список в файл и прочитать из него.2. Когда я запускаю
list_bam=$(for i in *.bam; do echo $i; done)
в своем каталоге , а затем звонюecho $list_bam
, я получаю список имен файлов.3. Однако, если команда, которую я выполняю внутри цикла, создает временный файл с тем же расширением, цикл также пытается обработать этот новый файл tmp. Это невозможно.
4. Мне это тоже кажется невозможным, вот почему я так растерян.
5. Я не могу воспроизвести эту проблему. Пример команды
for i in *.bam; do cp $i bu.$i; echo $i; sleep 0.1; done
работает только для исходных файлов, как и следовало ожидать.
Ответ №1:
Вместо цикла вы можете использовать find и xargs
find . -maxdepth 1 -type f -name "*.bam" -print0 |
xargs -0 -I{} bash -c 'echo "{}" > "{}.new.bam"'
или
find . -maxdepth 1 -type f -name "*.bam" -print0 |
xargs -0 -I{} bash -c 'echo "$1" > "$1.new.bam"' -- {}
пример:
$ 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
Комментарии:
1. Спасибо! Я постараюсь это реализовать 🙂
Ответ №2:
Возможно, вам следует убедиться, что ваше выражение *.bam
шара не может быть впоследствии интерпретировано чем-то вроде:
list_bam=$(ls *.bam)
...
…но, как заметил @glenn в комментариях, это плохая идея.
Что-то подобное должно быть сделано с использованием шаблона find ... -print0 | xargs -0 ...
команды.
Комментарии:
1. Почему вы не должны анализировать выходные данные ls —
list_bam=(*.bam)
тогдаfor bam_file in "${list_bam[@]}" ...
2. Хорошо подмечено. Я соответствующим образом уточнил ответ.
3. Спасибо! На данный момент это фактически решило мою проблему, я попытаюсь реализовать
find ... | xargs ...
версию позже.