Відповіді:
У GNU findви можете використовувати -printfдля цього параметр, наприклад:
find /dir1 -type f -printf "%f\n"
-oмають більш низький пріоритет , ніж ті, що припускаються -a, так що ви будете часто хочуть , щоб згрупувати ваші -oаргументи)
Якщо у знахідці немає опції -printf, ви також можете використовувати базове ім'я:
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
find . -type f -printf "%f\n"
Або ви можете використовувати мову програмування, наприклад, Ruby (1.9+)
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
Якщо ви хочете уявити собі башти (принаймні 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вихід. наприклад, вбивати файли в dir на основі імен іншого dir:
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стає найшвидшим, оскільки створення нових процесів є відносно дорогою операцією.
Як уже зазначалося, ви можете комбінувати 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.)