Как использовать команду find для вывода списка имен файлов, но не пути?
Я проверил несколько ответов в Интернете, но они не работают, когда -nameв команде есть параметр (возможно, я что-то делаю не так, не уверен). Я хотел бы указать только имена файлов (а не каталог / путь), и, чтобы усложнить, у меня такое же имя файла с другим расширением, поэтому мне нужно отфильтровать результат, используя -nameи -o, проблема в предложениях, которые я видел использовать либо -printfили basename, и они не работают, когда есть -name *.txt -o name *.pdf. Есть ли другой способ решить эту проблему?
Пример моих файлов:
/dir1/dir2/dir3/dir4/
/file1.txt
/file1.pdf
/file1.ods ...etc.
Меня интересует только перечисление одного или нескольких типов файлов для каждого списка (с использованием -nameдля фильтрации моих результатов.
Можно ли сделать это, используя только 1 findкоманду, или мне нужно сделать это за 2 шага (сохранить результат во временном файле, а затем отфильтровать / удалить каталог из временного файла)? Результатом, которого я пытаюсь добиться, является текстовый файл с именем файла в каждой строке:
file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.
Я использовал команду
find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"
Я использую GNU find.
Обновить
Оказалось, я должен поставить \(...\), как напомнил αғsнιη
Ответы
При использовании нескольких выражений в режиме логического ИЛИ -oвам необходимо заключить их все внутрь \( ... \), иначе всегда будет учитываться результат последнего выражения; и -printf '%f\n'используется для вывода имен файлов только с удаленными ведущими каталогами.
find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'
см man findпод ОПЕРАТОРАМИ раздела о ( expr ):
ОПЕРАТОРЫ
...(expr)
Приоритет силы. Поскольку круглые скобки являются специальными для оболочки, вам обычно нужно заключать их в кавычки.
поэтому вы можете использовать \( ... \)или '(' ... ')'(пробелы после и перед круглыми скобками важны), чтобы избежать их.
Как уже было сказано, вам нужно сгруппировать свои -nameтесты в скобках. Эти круглые скобки должны быть экранированы \( ... \)или '(' ... ')'заключены в кавычки, например, для защиты от оболочки (где в противном случае они обозначили бы подоболочку).
Используя стандарт find, а также немного упростив обработку суффиксов имени файла:
set -- txt pdf ods
for suffix do
set -- "$@" -o -name "*.$suffix"
shift
done
shift
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;
Это сначала устанавливает позиционные параметры в список суффиксов имени файла, которые мы хотели бы видеть (это также может быть взято из командной строки, если это сценарий), и создает список -nameтестов по ИЛИ . Затем это используется в findкомандной строке.
Затем сама findкоманда вызывает basenameутилиту для каждого найденного имени.
В качестве альтернативы мы могли бы вместо этого использовать подстановку параметра для удаления всех компонентов каждого пути, кроме имени файла, но для этого мы должны передать имена пути во встроенный sh -cскрипт:
# [...] as before [...]
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
for pathname do
printf "%s\n" "${pathname##*/}"
done' sh {} +
Я ожидал, что это будет работать быстрее, чем вариант с использованием basename, по крайней мере, если есть много имен файлов для обработки, хотя с GNU basenameиз coreutils вы можете использовать -aили --multipleнравится так:
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +
Это будет звонить basenameкак можно реже. Но опять же, если у вас установлен coreutils, у вас также может быть findutils с GNU find, и вы можете использовать его -printf '%f\n'для того же.