Belirli bir uzantıya sahip dosyaları yinelemeli olarak arayın


437

Benim bash (Son Ubuntu LTS Release) ile bir dizinde belirli bir uzantısı ve alt dizinleri ile tüm dosyaları bulmaya çalışıyorum.

Bir komut dosyasında yazılan budur:

#!/bin/bash

directory="/home/flip/Desktop"
suffix="in"

browsefolders ()
  for i in "$1"/*; 
  do
    echo "dir :$directory"
    echo "filename: $i"
    #   echo ${i#*.}
    extension=`echo "$i" | cut -d'.' -f2`
    echo "Erweiterung $extension"
    if     [ -f "$i" ]; then        

        if [ $extension == $suffix ]; then
            echo "$i ends with $in"

        else
            echo "$i does NOT end with $in"
        fi
    elif [ -d "$i" ]; then  
    browsefolders "$i"
    fi
  done
}
browsefolders  "$directory"

Ne yazık ki, bu komut dosyasını terminalde başlattığımda şöyle diyor:

[: 29: in: unexpected operator

( $extensionyerine 'in')

Burada neler oluyor, hata nerede? Ama bu süslü ayraç


2
Hata eksik bir '{'
shrewmouse

Yanıtlar:


750
find $directory -type f -name "*.in"

her şeyden biraz daha kısadır (ve daha güvenli - dosya adları ve dizin adlarındaki boşluklarla ilgilenir).

Komut dosyanız muhtemelen .adında bir girişi olmayan girişler için başarısız oluyor $extension.


16
evet, findvarsayılan olarak özyinelemelidir. isterseniz derinlikleri sınırlayabilirsiniz (kılavuz sayfasına bakınız).
Mat

1
Bulunan tüm dosyaları bir jar dosyasına argüman olarak aktarmak istiyorum. Bu nasıl yapılabilir?
Flip

8
@flip: bu farklı bir soru. Tam olarak ne yapmak istediğinizi ve şu ana kadar denediklerinizi ayrıntılı olarak açıklayan yeni bir soru gönderin.
Mat

Küçük bir düzeltme: "* .in" yerine "* .in" veya \ *. Kullanın, çünkü çift tırnaklar kabuk genişlemesini engellemez. Geçerli dizinde .in uzantılı bir dosya varsa, komut dosyanız düzgün çalışmaz.
Shnatsel

4
@Shnatsel: çift tırnak kabuk genişlemesini engeller. Denemek.
Mat

188
find {directory} -type f -name '*.extension'

Örnek:csv Geçerli dizindeki ve alt dizinlerindeki tüm dosyaları bulmak için şunu kullanın:

find . -type f -name '*.csv'

60

Kullandığım sözdizimi @Matt'ın önerdiğinden biraz farklı:

find $directory -type f -name \*.in

(daha az bir tuş vuruşu).


1
Geçerli dizinde .in uzantılı bir dosya varsa, Matt'in komut dosyası da çalışmazken, sizinki yine de çalışır. Bkz. Stackoverflow.com/questions/5927369/…
Shnatsel

4
@Shnatsel bu yorum (ve dolayısıyla sizinki) düz yanlıştır.
gniourf_gniourf

1
@gniourf_gniourf İfadeniz için bir miktar referans vermelisiniz, aksi takdirde sadece şunu iddia edebilirsiniz: "Hayır, yanılıyorsunuz". Ama aslında haklısın: gnu.org/software/bash/manual/html_node/Double-Quotes.html
Murmel

@ user1885518: Ben betiğin işe yaramadığını iddia eden adam olmalı, betiğin başarısız olduğu yerlerde bazı örnekler vermesi gerektiğini düşünüyorum. Komut dosyalarının olduğu yerlerde yorum bıraktığımda yaptığım şey budur: genellikle boşluklar, yeni satırlar, globlar vb. İçeren tırnak işaretleri ve dosya adları ile ilgilidir ve özellikle neden kırıldığını açıklarım.
gniourf_gniourf

2
Referans sağlamak bir tartışmada her zaman iyi bir yoldur, ilk kim olduğuna bağlı değildir. Yapmalı, yapmalısın.
Murmel

14

Kullanmadan find:

du -a $directory | awk '{print $2}' | grep '\.in$'

3
grepBurada gerçekten gerekli değildir. awkdüzenli ifadeleri vardır ve çıktısını bir kalıpla eşleşen değerlerle sınırlayabilir.
Kenster

Bu yöntem 100'lü terabayttan geçiyorsanız son derece kullanışlıdır. Bul komutunun işlenmesi çok zaman alıyor. Bu hemen başlar.
Protonova

1
awk|grepbir anti-kalıptır. Awk selamlamayı yapsın.
Jens

10
  1. {Sonra bir eksik varbrowsefolders ()
  2. Hepsi $inolmalı$suffix
  3. İle çizgi cutsadece orta kısmını alır front.middle.extension. Kabuk kılavuzunuzu ${varname%%pattern}ve arkadaşlarınızı okumalısınız .

Bunu kabuk komut dosyalarında bir alıştırma olarak yaptığınızı varsayıyorum, aksi takdirde findönerilen çözüm gitmek için bir yoldur.

Komut dosyası çalıştırmadan uygun kabuk sözdizimini kontrol etmek için kullanın sh -n scriptname.



7

findKomutu kullanmak burada yararlı olsa da , kabuğun kendisi herhangi bir üçüncü taraf aracı olmadan bu gereksinimi gerçekleştirmek için seçenekler sunar. bashKabuk Eğer özyinelemeli yolları altında dosya adları alabilirsiniz kullanarak genişletilmiş glob destek seçeneğini sağladığını istediğiniz uzantılı bir maç.

Genişletilmiş seçenek, aşağıdaki seçenek extglobkullanılarak ayarlanması gerekir shopt. Seçenekler -sdestek ile etkinleştirilir ve -uişaretlendiğinde devre dışı bırakılır . Ek olarak, birkaç seçenek daha kullanabilirsiniz, yani nullglobeşsiz bir kürenin tamamen süpürüldüğü ve sıfır kelime kümesiyle değiştirildiği. Ve globstarbu tüm dizinler aracılığıyla geri çekilmeyi sağlar

shopt -s extglob nullglob globstar

Şimdi yapmanız gereken, aşağıdaki gibi yapabileceğiniz belirli bir uzantının dosyalarını dahil etmek için glob ifadesini oluşturmaktır. Glob sonuçlarını doldurmak için bir dizi kullanıyoruz, çünkü düzgün bir şekilde alıntılandığında ve genişletildiğinde, özel karakterlere sahip dosya adları sağlam kalacak ve kabuk tarafından kelime bölünmesi nedeniyle kırılmayacaktı.

Örneğin *.csv, özyinelemeli yollardaki tüm dosyaları listelemek için

fileList=(**/*.csv)

Bu seçenek **, alt klasörler aracılığıyla yineleme yapmak ve *.csvbelirtilen uzantıların herhangi bir dosyasını içerecek şekilde glob genişletmesidir. Şimdi gerçek dosyaları yazdırmak için

printf '%s\n' "${fileList[@]}"

Bir dizi kullanmak ve uygun bir alıntı yapmak, kabuk komut dosyalarında kullanıldığında doğru yoldur, ancak etkileşimli kullanım lsiçin glob ifadesi ile

ls -1 -- **/*.csv

Bu, çok sayıda dosyayla eşleşecek şekilde çok iyi genişletilebilir (yani, birden fazla uzantıyla biten dosya ( findkomutta birden çok bayrak eklemeye benzer ). Örneğin, uzantılar *.gifgibi tüm özyinelemeli görüntü dosyalarını almanız gerektiğini düşünün *.pngve *.jpgyapmanız gereken tek şey

ls -1 -- **/+(*.jpg|*.gif|*.png)

Bu da olumsuz sonuçlara ulaşacak şekilde genişletilebilir. Aynı sözdizimiyle, glob'un sonuçları belirli türdeki dosyaları hariç tutmak için kullanılabilir. Yukarıdaki uzantılara sahip dosya adlarını hariç tutmak istediğinizi varsayalım,

excludeResults=()
excludeResults=(**/!(*.jpg|*.gif|*.png))
printf '%s\n' "${excludeResults[@]}"

Yapı !(), içinde listelenen dosya uzantılarının hiçbirini içermeyen bir olumsuz işlemdir ve |tıpkı glob'ların OR eşleşmesini yapmak için Genişletilmiş Düzenli İfadeler kitaplığında kullanılan bir alternatif operatörüdür.

Bu genişletilmiş glob desteğinin POSIX bourne kabuğunda ve yalnızca son sürümlerine özgü olmadığını unutmayın bash. Bu nedenle POSIX ve bashkabuklarda çalışan komut dosyalarının taşınabilirliğini düşünüyorsanız , bu seçenek doğru olmaz.


6

pom.xmlGeçerli dizininizdeki tüm dosyaları bulmak ve yazdırmak için şunları kullanabilirsiniz:

find . -name 'pom.xml' -print

1
find $directory -type f -name "*.in"|grep $substring

0
for file in "${LOCATION_VAR}"/*.zip
do
  echo "$file"
done 

1
Bu kod soruyu cevaplayabilirken, bu kodun soruyu neden ve / veya nasıl cevapladığı konusunda ek bağlam sağlamak uzun vadeli değerini arttırır.
rollstuhlfahrer
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.