MyTetra Share
Делитесь знаниями!
Как в Bash обойти все имена файлов, полученных от команды find, в которых могут встречаться пробельные символы?
Время создания: 17.08.2024 00:26
Автор: Xintrea
Текстовые метки: bash, find, обойти, перебор, вывод, цикл, for, while, имя, файл, имя файла, пробел, пробельный, символ, содержит
Раздел: Компьютер - Linux - Bash - Команды и скрипты
Запись: xintrea/mytetra_syncro/master/base/1723843601hx0ljkn11u/text.html на raw.github.com

Если попытаться в интернете найти ответ на вопрос, как в цикле вывести имена файлов из директории и всех ее поддиректорий, с учетом того что имена файлов могут содержать пробелы, то будет выдано много взаимоисключающих решений. Множество решений будет базироваться на применении команды 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 перебрать имена файлов, с учетом того, что в них могут быть пробелы.


Так же в этом разделе:
 
MyTetra Share v.0.65
Яндекс индекс цитирования