Если попытаться в интернете найти ответ на вопрос, как в цикле вывести имена файлов из директории и всех ее поддиректорий, с учетом того что имена файлов могут содержать пробелы, то будет выдано много взаимоисключающих решений. Множество решений будет базироваться на применении команды find в текущей директории. Однако в них, традиционно, забывается о том что в именах фалов могут быть пробелы.
Для решения проблем с пробелами, чаще всего будут советовать вместо команды find использовать просто файловую маску, заканчивающуюся на звездочку:
for i in "./*"; do echo ${i}; done
И совершенно не думают о том, что данная команда не обработает файлы в подкаталогах.
Итак, какое же будет самое простое и правильное решение для перебора файлов в текущем каталоге и подкаталогах? Синтаксис будет следующим:
#!/bin/bash
find -name \*.mp3 \
-or -name \*.MP3 \
-or -name \*.Mp3 \
-or -name \*.ogg \
| while read -r file;
do
echo "Processing ${file}"
done
Этот метод действительно работает как ожидается. Однако в зубодробительных обсуждениях можно найти более сложное решение, которое по мнению авторов лишено некоторых побочных эффектов, которые могут появиться при использовании экзотических символов в именах файлов. Поэтому, для пущей надежности, надо пользоваться опцией -print0. Она заставляет find выводить результаты с использованием нулевого байта в качестве разделителя (вместо пробела или новой строки):
#!/bin/bash
find \( -name \*.mp3 \
-or -name \*.MP3 \
-or -name \*.Mp3 \
-or -name \*.ogg \
\) -print0 \
| while IFS= read -r -d '' file;
do
echo "Processing ${file}"
done
Здесь вокруг множества условий поиска поставлены круглые скобки. Они нужны из-за того, что опция -print0 применяется только к самой ближайшей части условия (если скобок нет). То есть без скобок, опция -print0 будет влиять только на последнюю часть условия, а именно на "-or -name \*.ogg". И без круглых скобок только эта часть будет специальным образом обрабатываться. А это не то что нужно.
Касательно выкрутасов в команде while, имеется следующее пояснение:
- IFS= предотвращает обработку пробелов в качестве разделителей.
- -r указывает read не интерпретировать обратные слеши (\) как escape-последовательности.
- -d '' устанавливает разделитель строк на нулевой байт (\0), что обеспечивает корректную работу с именами файлов, содержащими пробелы и другие специальные символы, т. е. позволяет правильно обработать вывод команды find с опцией -print0.
В общем, два вышеприведенных варианта - это готовое решение вопроса о том, как в Linux перебрать имена файлов, с учетом того, что в них могут быть пробелы.