Ответы:
В GNU findвы можете использовать -printfпараметр для этого, например:
find /dir1 -type f -printf "%f\n"
-oимеет более низкий приоритет, чем подразумеваемый -a, поэтому вы часто захотите сгруппировать свои -oаргументы)
Если в вашем поиске нет опции -printf, вы также можете использовать basename:
find ./dir1 -type f -exec basename {} \;
... {} ';'
Используйте -execdirкоторый автоматически содержит текущий файл {}, например:
find . -type f -execdir echo '{}' ';'
Вы также можете использовать $PWDвместо .(в некоторых системах это не приведет к появлению дополнительной точки спереди).
Если у вас все еще есть лишняя точка, вы можете запустить:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
-execdirПервична идентична-execпервичный за исключением того , утилита будет выполнена из каталога, держит текущий файл .
Когда используется +вместо ;, то {}заменяется таким количеством путей, сколько возможно для каждого вызова утилиты. Другими словами, он напечатает все имена файлов в одну строку.
./filenameвместо filename. В зависимости от ваших потребностей, это может или не может быть хорошо.
$PWDвместо ..
Если вы используете GNU найти
find . -type f -printf "%f\n"
Или вы можете использовать язык программирования, такой как Ruby (1.9+)
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
Если вам нравится решение bash (как минимум 4)
shopt -s globstar
for file in **; do echo ${file##*/}; done
Если вы хотите выполнить какое-либо действие только с именем файла, использовать basenameможет быть сложно.
Например это:
find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \;
будет просто повторять базовое имя /my/found/path. Не то, что мы хотим, если мы хотим выполнить по имени файла.
Но вы можете затем xargsна выходе. например, чтобы убить файлы в каталоге, основываясь на именах в другом каталоге:
cd dirIwantToRMin;
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; | xargs rm
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \;
-execи -execdirмедленно, xargsэто король.
$ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \
f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l; \
f -print0 | xargs -0 basename | wc -l
139
0m01.17s real 0m00.20s user 0m00.93s system
139
0m01.16s real 0m00.20s user 0m00.92s system
139
0m01.05s real 0m00.17s user 0m00.85s system
139
0m00.93s real 0m00.17s user 0m00.85s system
139
0m00.88s real 0m00.12s user 0m00.75s system
xargsПараллелизм также помогает.
Как ни странно, я не могу объяснить последний случай xargsбез -n1. Это дает правильный результат, и это самый быстрый¯\_(ツ)_/¯
( basenameпринимает только 1 аргумент пути, но xargsотправит их все (на самом деле 5000) без -n1. не работает на linux и openbsd, только macOS ...)
Несколько больших цифр из системы Linux, чтобы увидеть, как это -execdirпомогает, но все же намного медленнее, чем параллель xargs:
$ alias f='time find /usr/ -maxdepth 5 -type d'
$ f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l
2358
3.63s real 0.10s user 0.41s system
2358
1.53s real 0.05s user 0.31s system
2358
1.30s real 0.03s user 0.21s system
2358
0.41s real 0.03s user 0.25s system
findэто -execdirстановится самым быстрым, поскольку создание новых процессов - относительно дорогая операция.
Честно говоря, basenameи dirnameрешения проще, но вы также можете проверить это:
find . -type f | grep -oP "[^/]*$"
или
find . -type f | rev | cut -d '/' -f1 | rev
или
find . -type f | sed "s/.*\///"
Как уже отмечали другие, вы можете комбинировать findи basename, но по умолчанию basenameпрограмма будет работать только по одному пути за раз, поэтому исполняемый файл придется запускать один раз для каждого пути (используя либо find ... -execили find ... | xargs -n 1), что потенциально может быть медленным.
Если вы используете -aопцию on basename, то он может принимать несколько имен файлов за один вызов, что означает, что вы можете затем использовать xargsбез -n 1, чтобы сгруппировать пути вместе в гораздо меньшее количество вызовов basename, что должно быть более эффективным.
Пример:
find /dir1 -type f -print0 | xargs -0 basename -a
Здесь я включил -print0и -0(который должен использоваться вместе), чтобы справиться с любым пробелом в именах файлов и каталогов.
Вот сравнение времени, между xargs basename -aи xargs -n1 basenameверсиями. (Для сравнения «похоже на аналогию» время, указанное здесь, указано после первоначального фиктивного запуска, так что они оба выполняются после того, как метаданные файла уже скопированы в кэш ввода / вывода.) Я передал выходные данные в cksumв обоих случаях просто для демонстрации того, что вывод не зависит от используемого метода.
$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
2532163462 546663
real 0m0.063s
user 0m0.058s
sys 0m0.040s
$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum'
2532163462 546663
real 0m14.504s
user 0m12.474s
sys 0m3.109s
Как вы можете видеть, это действительно намного быстрее, чтобы избежать запуска basenameкаждый раз.
basenameбудут приниматься несколько имен файлов без дополнительных аргументов командной строки. Использование -aздесь на Linux. ( basename --versionговорит мне basename (GNU coreutils) 8.28.)