Ответы:
В 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
.)