Dosya adlarını listelemek için ancak yolu listelemek için find komutu nasıl kullanılır?

Jan 06 2021

Çevrimiçi olarak bazı cevapları kontrol ettim, ancak -namekomutta bir parametre olduğunda çalışmıyorlar (belki yanlış bir şey yapıyorum, emin değilim). Yapmak istediğim şey sadece dosya adlarını listelemek (dizin / yol değil) ve daha karmaşık hale getirmek için, farklı uzantılarla aynı dosya adına sahibim, bu yüzden sonucu -nameve kullanarak filtrelemem gerekiyor -o, sorun şu önerilerim ya ya -printfda kullandığını gördü basenameve var olduğunda bunlar iyi çalışmıyor -name *.txt -o name *.pdf. Bu sorunu çözmenin başka bir yolu var mı?

Dosyalarımın örneği:

/dir1/dir2/dir3/dir4/
                    /file1.txt
                    /file1.pdf
                    /file1.ods ...etc.

Her giriş için yalnızca bir veya daha fazla dosya türünü listelemekle ilgileniyorum (kullanarak -namesonuçlarımı filtrelemek için kullanarak .

Bunu yalnızca 1 findkomut kullanarak gerçekleştirmek mümkün mü yoksa bunu 2 adımda yapmak zorundayım (sonucu geçici bir dosyaya kaydetmek, ardından dizini geçici dosyadan filtrelemek / ayırmak)? Başarmaya çalıştığım sonuç, her satırda dosya adı olan bir metin dosyası:

file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.

Kullandığım komut

find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"

GNU bulmayı kullanıyorum.

Güncelleme

\(...\)Αғsнιη tarafından hatırlatıldığı gibi , koymak zorunda olduğum ortaya çıktı.

Yanıtlar

3 αғsнιη Jan 06 2021 at 21:02

Mantıksal OR modunda birden çok ifade kullanırken -ohepsini içine almanız gerekir \( ... \), aksi takdirde son ifade sonucuna her zaman saygı gösterilir; ve -printf '%f\n'dosyaların adını yalnızca önde gelen dizinleri kaldırarak yazdırmak için kullanılır.

find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'

bkz man findaltında OPERATÖRLERİ hakkında bölümüne ( expr ):

OPERATÖRLER
...

(ifade)
Öncelik zorla . Parantezler kabuğa özel olduğundan, normalde bunları tırnak içine almanız gerekir.

bu yüzden onlardan kaçmak için \( ... \)veya '(' ... ')'(parantezden sonraki ve önceki boşluklar önemlidir) kullanabilirsiniz.

1 Kusalananda Jan 06 2021 at 22:58

Daha önce de belirtildiği gibi, -nametestlerinizi parantez içinde gruplamanız gerekir . Bu parantezlerin \( ... \), örneğin '(' ... ')'onları kabuktan korumak için (aksi takdirde bir alt kabuk olarak adlandırılacakları) olarak çıkarılması veya alıntılanması gerekir .

Standart kullanmak findve ayrıca dosya adı son eklerinin işlenmesini biraz daha kolaylaştırmak:

set -- txt pdf ods

for suffix do
    set -- "$@" -o -name "*.$suffix"
    shift
done
shift

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;

Bu, ilk olarak konumsal parametreleri görmek istediğimiz dosya adı sonekleri listesine ayarlar (bu bir komut dosyası ise komut satırından da alınabilir) ve -nametestlerin OR listesini oluşturur . Bu daha sonra findkomut satırında kullanılır.

findKomut kendisi aranmamanızı basenameher bulunan adı için yarar.

Alternatif olarak, her bir yol adının dosya adı bileşeni hariç tümünü kaldırmak için bir parametre ikamesi kullanabiliriz, ancak bunu yapmak için yol adlarını bir satır içi sh -cbetiğe aktarmalıyız:

# [...] as before [...]

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
    for pathname do
        printf "%s\n" "${pathname##*/}"
    done' sh {} +

Bunun kullanılan varyasyondan daha hızlı çalışmasını beklerdim basename, en azından işlenecek çok sayıda dosya adı varsa, ancak basenamecoreutils'teki GNU ile bunu kullanabilir -aveya --multiplebeğenebilirsiniz:

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +

Bu basenamemümkün olduğunca az kez arayacaktır . Ama yine de, eğer çekirdek temeller yüklüyse, GNU ile de bulma araçlarına sahip findolabilirsiniz -printf '%f\n've aynı şeyi yapmak için kullanabilirsiniz .