Вопрос или проблема
Краткий фон; у меня есть скрипт, который я запускаю, чтобы помещать новые эпизоды ТВ в свою библиотеку после конверсии и именования. Он просто находит соответствующий каталог по имени. Недавно я проверял свои диски с помощью 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
)"
Объяснение кода
-L
: Эта опция позволяетfind
следовать символическим ссылкам.\( -path '../To Sort' -o -path '../lost+found' \)
: Этот блок определяет, какие пути следует исключить. Оператор-o
означает "или".-prune
: Этот параметр прерывает дальнейший поиск в указанных путях.-name "$show"
: Здесь происходит поиск файлов с именем, соответствующим переменной$show
.-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
поможет избежать ошибок и упростит вашу работу со скриптами организации файлов. Не забывайте о важности хранения результатов в массиве для дальнейшей обработки, а также о возможных проблемах с символами подстановки в именах файлов. Применение предложенных методов улучшит ваш рабочий процесс и сделает его более надежным.