Yalnızca Linux 'find' ile dosya adı nasıl alınır?


266

Ben dizindeki tüm dosyalara find kullanıyorum, bu yüzden yolların bir listesini almak. Ancak, sadece dosya adlarına ihtiyacım var. yani anlıyorum ./dir1/dir2/file.txtve almak istiyorumfile.txt

Yanıtlar:


359

GNU'da bunun için parametre findkullanabilirsiniz -printf, örneğin:

find /dir1 -type f -printf "%f\n"

9
Açıkçası cevap , ama detay eksik.
Jason McCreary

25
bu sadece GNU içindir
Osama F Elias

3
Birden fazla dosya türü kullandığımda bu benim için çalışmıyor (-o anahtarı)
Urchin

9
find: -printf: bilinmeyen birincil veya operatör
holms

Bu kadar uzun Doğru mantık var olduğu olmamalı @Urchin sebep yok (yani -oima daha düşük önceliğe sahiptir -asık sık grubun olmak istemelerini sağlamak, -oargümanlar)
eski durumuna Monica Lütfen

157

Bulmanızın bir -printf seçeneği yoksa basename'yi de kullanabilirsiniz:

find ./dir1 -type f -exec basename {} \;

17
Noktalı virgülden alıntı yapmak, ... {} ';'
ayrılmanın

28

Kullanım -execdirotomatik geçerli dosyayı tutan {}örneğin,:

find . -type f -execdir echo '{}' ';'

Bunun $PWDyerine. (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 ...] ;

-execdirBirincil aynıdır -execyardı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.


Bunun ./filenameyerine alıyorum filename. İhtiyaçlarınıza bağlı olarak, iyi olabilir veya olmayabilir.
user276648

@ user276648 $PWDyerine deneyin ..
kenorb

24

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

Yardım etmek için verdiğiniz yanıttan ilham aldım: serverfault.com/a/745968/329412
Nolwennig

11

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

yankı yankı -find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \;
commonpike

7

Mac'te (BSD find) şunları kullanın:

find /dir1 -type f -exec basename {} \;

1

-execve -execdiryavaşlar, xargskral.

$ 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

xargsParalellik de yardımcı olur.

Funnily yeterince xargsolmadan son durumda açıklayamam-n1 . Doğru sonucu verir ve en hızlısıdır¯\_(ツ)_/¯

( basenamesadece 1 yol argümanını alır, ancak xargshepsini gönderir (aslında 5000) -n1linux ve openbsd üzerinde çalışmaz, sadece macOS ...)

Bir linux sisteminden bazı büyük sayılar nasıl -execdiryardı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

1
Sadece bir daha fazla veri noktası: OpenBSD'deki bir uzun çalışan findo -execdiryeni süreçlerin yaratılması nispeten pahalı bir işlemdir olarak bu hızlı olur.
eksi

1

Dürüst olmak gerekirse basenameve 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/.*\///"

0

Diğerlerinin işaret ettiği gibi, birleştirebilirsiniz findve basenameancak varsayılan olarak basenameprogram 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 ... -execveya birini kullanarak find ... | xargs -n 1), bu da yavaş olabilir.

Eğer kullanırsanız -aseçeneği basename, o zaman birden tek çağırma dosya adlarını, daha sonra kullanabileceği araçlar kabul edebilir xargsolmadan -n 1halinin çağrıları çok daha az sayıda içine yolları gruplandırmak amacıyla basenamedaha verimli olmalı.

Misal:

find /dir1 -type f -print0 | xargs -0 basename -a

Buraya -print0ve-0 , dosya ve dizin adlarındaki herhangi bir boşlukla başa çıkmak (birlikte kullanılmalıdır) ekledim.

İşte xargs basename -ave xargs -n1 basenamesü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ışı cksumher 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, basenameher seferinde lansmandan kaçınmak gerçekten çok daha hızlı .


@Minusf'tan gelen cevabı daha ayrıntılı bir şekilde okuduğumda, Mac'te basenameherhangi bir ek komut satırı argümanı gerekmeden birden fazla dosya adını kabul edeceğini görüyorum . -aBurada kullanımı Linux'ta. ( basename --versionbana söyler basename (GNU coreutils) 8.28.)
alaniwi

-3

Sadece en yeni dosya adını veren bir çözüm (makandracards sayfasında) buldum:

ls -1tr * | tail -1

(teşekkürler Arne Hartherz'e gider)

Ben için kullandım cp:

cp $(ls -1tr * | tail -1) /tmp/

2
Bu soruya hiç cevap vermiyor.
kenorb
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.