Відповіді:
У 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
.)