Я использую find для всех файлов в каталоге, поэтому я получаю список путей. Однако мне нужны только имена файлов. т.е. я получаю ./dir1/dir2/file.txt
и хочу получить file.txt
Как получить только имя файла с Linux 'find'?
Ответы:
В GNU find
для этого можно использовать параметр -printf
, например:
find /dir1 -type f -printf "%f\n"
Если в вашей находке нет опции -printf, вы также можете использовать basename:
find ./dir1 -type f -exec basename {} \;
... {} ';'
28.12.2012 Используйте -execdir
, который автоматически сохраняет текущий файл в {}
, например:
find . -type f -execdir echo '{}' ';'
Вы также можете использовать $PWD
вместо .
(в некоторых системах это не приведет к появлению дополнительной точки спереди).
Если у вас все еще есть лишняя точка, вы также можете запустить:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
Первичный
-execdir
идентичен первичному-exec
за исключением того, что утилита будет запускаться из каталога, содержащего текущий файл.
Когда используется +
вместо ;
, тогда {}
заменяется максимально возможным количеством путей для каждого вызова утилиты. Другими словами, он напечатает все имена файлов в одной строке.
./filename
вместо filename
. В зависимости от ваших потребностей, это может подойти, а может и не подойти. 05.01.2017 $PWD
вместо .
. 05.01.2017 Если вы используете GNU find
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 {} \;
25.04.2018 На Mac (BSD find
) используйте:
find /dir1 -type f -exec basename {} \;
Как указывали другие, вы можете комбинировать find
и basename
, но по умолчанию программа basename
будет работать только по одному пути за раз, поэтому исполняемый файл должен будет запускаться один раз для каждого пути (используя либо find ... -exec
, либо find ... | xargs -n 1
), что потенциально может быть медленным.
Если вы используете параметр -a
на 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
.) 22.05.2020 -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
становится самым быстрым, поскольку создание новых процессов является относительно дорогостоящей операцией. 12.02.2020 Честно говоря, решения basename
и dirname
проще, но вы также можете проверить это:
find . -type f | grep -oP "[^/]*$"
or
find . -type f | rev | cut -d '/' -f1 | rev
or
find . -type f | sed "s/.*\///"
rev
, какой ловкий трюк! 29.05.2021 Я нашел решение (на странице makandracards), которое дает только самое новое имя файла:
ls -1tr * | tail -1
(спасибо Arne Hartherz)
Я использовал его для cp
:
cp $(ls -1tr * | tail -1) /tmp/
-o
имеет более низкий приоритет, чем подразумеваемый-a
, поэтому вы часто захотите сгруппировать свои-o
аргументы) 29.07.2014find ./ -name "*" -printf "%f\n" | xargs grep "searchName"
Это не сработает, будет только напечатано: about.php: Нет такого файла или каталога grep: site-themes.php: Нет такого файла или каталога Илиfind ./ -name "*" | xargs grep "searchName" -printf "%f\n"
все еще ошибка 05.10.2014find -printf "%f\n" -exec echo {} \;
показывает, что исходное имя файла передается вперед 23.11.2017