Yanıtlar:
GNU'da bunun için parametre find
kullanabilirsiniz -printf
, örneğin:
find /dir1 -type f -printf "%f\n"
-o
ima daha düşük önceliğe sahiptir -a
sık sık grubun olmak istemelerini sağlamak, -o
argümanlar)
Bulmanızın bir -printf seçeneği yoksa basename'yi de kullanabilirsiniz:
find ./dir1 -type f -exec basename {} \;
... {} ';'
Kullanım -execdir
otomatik geçerli dosyayı tutan {}
örneğin,:
find . -type f -execdir echo '{}' ';'
Bunun $PWD
yerine.
(bazı sistemlerde ön tarafta fazladan bir nokta oluşturmaz).
Hala fazladan bir noktanız varsa, alternatif olarak şunları da çalıştırabilirsiniz:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
-execdir
Birincil aynıdır-exec
yardımcı dizininden yürütülür haricinde, primer mevcut dosya tutar .
+
Bunun yerine kullanıldığında ;
, {}
her bir yardımcı program çağrısı için mümkün olduğunca çok yol adı ile değiştirilir. Başka bir deyişle, tüm dosya adlarını tek bir satıra yazdırır.
./filename
yerine alıyorum filename
. İhtiyaçlarınıza bağlı olarak, iyi olabilir veya olmayabilir.
$PWD
yerine deneyin .
.
GNU find kullanıyorsanız
find . -type f -printf "%f\n"
Veya Ruby (1.9+) gibi bir programlama dili kullanabilirsiniz.
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
Bir bash (en az 4) çözelti istiyorsanız
shopt -s globstar
for file in **; do echo ${file##*/}; done
Yalnızca dosya adına karşı bir eylem çalıştırmak istiyorsanız basename
, kullanımı zor olabilir.
Örneğin bu:
find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \;
sadece basename yankılanacak /my/found/path
. Dosya adında yürütmek istiyorsak istediğimiz gibi değil.
Ama sonra xargs
çıktıyı alabilirsiniz. örneğin bir dizindeki dosyaları başka bir dizindeki isimlere göre öldürmek için:
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
ve -execdir
yavaşlar, xargs
kral.
$ 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
Paralellik de yardımcı olur.
Funnily yeterince xargs
olmadan son durumda açıklayamam-n1
. Doğru sonucu verir ve en hızlısıdır¯\_(ツ)_/¯
( basename
sadece 1 yol argümanını alır, ancak xargs
hepsini gönderir (aslında 5000) -n1
linux ve openbsd üzerinde çalışmaz, sadece macOS ...)
Bir linux sisteminden bazı büyük sayılar nasıl -execdir
yardımcı olduğunu görmek için , ancak yine de bir paralelden çok daha yavaş 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
o -execdir
yeni süreçlerin yaratılması nispeten pahalı bir işlemdir olarak bu hızlı olur.
Dürüst olmak gerekirse basename
ve dirname
çözümler daha kolaydır, ancak şunları da kontrol edebilirsiniz:
find . -type f | grep -oP "[^/]*$"
veya
find . -type f | rev | cut -d '/' -f1 | rev
veya
find . -type f | sed "s/.*\///"
Diğerlerinin işaret ettiği gibi, birleştirebilirsiniz find
ve basename
ancak varsayılan olarak basename
program her seferinde yalnızca bir yolda çalışır, bu nedenle yürütülebilir dosya her yol için bir kez başlatılmalıdır ( find ... -exec
veya birini kullanarak find ... | xargs -n 1
), bu da yavaş olabilir.
Eğer kullanırsanız -a
seçeneği basename
, o zaman birden tek çağırma dosya adlarını, daha sonra kullanabileceği araçlar kabul edebilir xargs
olmadan -n 1
halinin çağrıları çok daha az sayıda içine yolları gruplandırmak amacıyla basename
daha verimli olmalı.
Misal:
find /dir1 -type f -print0 | xargs -0 basename -a
Buraya -print0
ve-0
, dosya ve dizin adlarındaki herhangi bir boşlukla başa çıkmak (birlikte kullanılmalıdır) ekledim.
İşte xargs basename -a
ve xargs -n1 basename
sürümleri arasında bir zamanlama karşılaştırması . (Benzeri benzeri bir karşılaştırma uğruna, burada bildirilen zamanlamalar bir ilk kukla çalıştırmadan sonradır, böylece her ikisi de dosya meta verileri zaten G / Ç önbelleğine kopyalandıktan sonra yapılır.) Çıkışı cksum
her iki durumda da, çıktının kullanılan yöntemden bağımsız olduğunu göstermek için.
$ 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
Gördüğünüz gibi, basename
her seferinde lansmandan kaçınmak gerçekten çok daha hızlı .
basename
herhangi bir ek komut satırı argümanı gerekmeden birden fazla dosya adını kabul edeceğini görüyorum . -a
Burada kullanımı Linux'ta. ( basename --version
bana söyler basename (GNU coreutils) 8.28
.)