Bash – Проблемы с командой find и исключением путей

Вопрос или проблема

Краткий фон; у меня есть скрипт, который я запускаю, чтобы помещать новые эпизоды ТВ в свою библиотеку после конверсии и именования. Он просто находит соответствующий каталог по имени. Недавно я проверял свои диски с помощью fsck, и он предупредил меня, что у меня отсутствует lost+found и воссоздал его. Теперь мой старый скрипт выдает предупреждение (но работает).

Старая команда:

find -L ../ -name "$show" -not -path "../To Sort/*"

Она запускается в каждом каталоге в To Sort и ищет по всем другим каталогам в родительском каталоге To Sort.

Старая ошибка:

find: ‘../lost+found’: Доступ запрещен

В поисках способа остановить попытки обращения к lost+found, я узнал, что -not -path не является правильным способом его использования, и мне следует использовать -prune; так что я несколько раз пытался сделать новый, но это предел моих возможностей:

found="$(find -L ../ \( -path "../To Sort" -o -path "../lost+found" \) -prune -o \ ../ -name "$show" )"

И теперь ошибки:

find: пути должны предшествовать выражению: ` ../’

Ну, есть этот лишний \ ../ посередине, который не имеет смысла. Также вам не хватает -print, чтобы избежать применения глобального действия -print ко всем обрезанным путям:

found="$(
  find -L .. '(' -path '../To Sort' -o -path '../lost+found' ')' -prune -o \
             -name "$show" -print
)"

Обратите внимание на \ в конце строки для продолжения строки, чтобы разбить эту длинную строку на две для улучшения читаемости; как только перед любым символом, кроме переноса строки, \ действует как оператор экранирования, так что перед пробелом, как в вашем коде, это сделает его буквальным символом пробела.

Но с этим кодом соответствующие пути окажутся конкатенированными с символами новой строки между ними в скалярной переменной. Будет более разумно хранить их в массиве.

Если использовать bash 4.4 или новее:

readarray -td '' files < <(
  find -L .. '(' -path '../To Sort' -o -path '../lost+found' ')' -prune -o \
    -name "$show" -print0
)

Обратите внимание на -print0 вместо -print (и соответствующий -d '' для readarray, чтобы разбить на NULы), чтобы пути файлов разделялись с помощью байтов NUL, единственного байтового значения, которое не может встречаться в пути файла.

Теперь вы можете передать элементы этого массива команде, такой как ls, с помощью:

ls -ld -- "${files[@]}"

Или сообщить о количестве совпадений с:

echo "${#files[@]} match${files[1]+es} found"

Также имейте в виду, что -name принимает шаблон. Если вы хотите точное совпадение, а название вашего шоу может содержать символы подстановки, такие как ?, *, \ или [...], вам необходимо их экранировать, предваряя их \.

С zsh вместо bash вы также можете сделать:

set -o extendedglob
files=( ../{,^To\ Sort/***/}$show(N) )

Что будет сначала расширено до:

files=( ../$show(N) ../^To\ Sort/***/$show(N) )

И затем каждая подстановка будет расширена отдельно, хотя и в стиле nullglob с квалификатором N, так что вы получите ../$show, если он существует, + все, что ниже в каталогах .., за исключением To Sort в рекурсивном спуске, который следует за символическими ссылками, как делает ваш find -L.

Здесь $show не принимается как шаблон, и вы получаете отсортированный список, а скрытые файлы автоматически пропускаются. Передача списка команде также проще: ls -ld -- $files. А также получение количества: $#files так, как в csh (хотя ${#files[@]} так же работает в ksh).

Ответ или решение

Использование команды find в Bash для исключения путей

В данной статье мы рассмотрим, как правильно использовать команду find в Bash, чтобы искать файлы и исключать нежелательные директории, такие как lost+found. Это может быть особенно полезно, если у вас есть сценарий, который вы используете для организации медиафайлов, например, для фильмов или телепередач, и который в последнее время выдаёт ошибки.

Проблема

При выполнении команды find в вашей системе вы сталкиваетесь с сообщением об ошибке, называющим lost+found, что может происходить после выполнения операций проверки файловой системы, таких как fsck. Ваш исходный код выглядел следующим образом:

find -L ../ -name "$show" -not -path "../To Sort/*"

Ошибка

Вы получили ошибку:

find: ‘../lost+found’: Permission denied

Это происходит из-за того, что команда find пытается просмотреть директорию, доступ к которой ограничен. Для решения этой проблемы рекомендуется использовать флаг -prune, который позволяет исключать определённые пути из процесса поиска.

Оптимизированный подход

Чтобы улучшить ваш исходный код и исключить директории, вы можете использовать следующую конструкцию:

found="$(
  find -L .. \( -path '../To Sort' -o -path '../lost+found' \) -prune -o \
    -name "$show" -print
)"

Объяснение кода

  1. -L: Эта опция позволяет find следовать символическим ссылкам.
  2. \( -path '../To Sort' -o -path '../lost+found' \): Этот блок определяет, какие пути следует исключить. Оператор -o означает "или".
  3. -prune: Этот параметр прерывает дальнейший поиск в указанных путях.
  4. -name "$show": Здесь происходит поиск файлов с именем, соответствующим переменной $show.
  5. -print: Это действие выводит найденные пути. Без этого по умолчанию find будет пытаться дополнительно выполнить действие для всех найденных путей, что может привести к ошибкам для исключенных.

Использование массивов для хранения результатов

Чтобы упростить дальнейшую работу с найденными файлами, имеет смысл хранить результаты в массиве. Если вы используете Bash версии 4.4 или выше, вы можете использовать следующую конструкцию:

readarray -td '' files < <(
  find -L .. \( -path '../To Sort' -o -path '../lost+found' \) -prune -o \
    -name "$show" -print0
)

Объяснение кода

  • readarray: Эта команда считывает строки в массив. Опция -td '' позволяет использовать в качестве разделителя нуль-байт, что гарантирует, что пути не будут нарушены, даже если они содержат пробелы.
  • -print0: Это действие выводит найденные пути с нуль-байтами в качестве разделителей.

После выполнения вышеуказанного кода, вы можете манипулировать массивом files. Например, для отображения найденных файлов можно воспользоваться следующей командой:

ls -ld -- "${files[@]}"

Подсчет найденных файлов

Чтобы вывести количество найденных совпадений, используйте следующую конструкцию:

echo "${#files[@]} match${files[1]+es} found"

Этот код печатает количество найденных файлов, добавляя "es" только в случае, если файлов больше одного.

Заключение

Правильное использование команды find в сочетании с исключением определенных путей с помощью параметра -prune поможет избежать ошибок и упростит вашу работу со скриптами организации файлов. Не забывайте о важности хранения результатов в массиве для дальнейшей обработки, а также о возможных проблемах с символами подстановки в именах файлов. Применение предложенных методов улучшит ваш рабочий процесс и сделает его более надежным.

Оцените материал
Добавить комментарий

Капча загружается...