Geçerli dizindeki tüm dosyalara özyinelemeli olarak ne genişler?


92

**/*.extEşleşen tüm alt dizinlerdeki tüm dosyalara genişlediğini biliyorum *.ext, ancak geçerli dizindeki tüm bu tür dosyaları da içeren benzer bir genişletme nedir?


4
Benim bash'ım idare etmiyor **/*.ext. İşe yaradığına emin misin?
— Tangens

@tangens globstarDennis cevabına göre seçeneği etkinleştirmelisiniz .
— kenorb

Yanıtlar:


111

Bu Bash 4'te çalışacak:

ls -l {,**/}*.ext

Çift yıldız işaretli kürenin çalışması için, globstarseçeneğin ayarlanması gerekir (varsayılan: açık):

shopt -s globstar

Kimden man bash:

    Globstar
                  Ayarlanırsa, dosya adı genişletmede kullanılan kalıp **
                  metin bir dosya ve sıfır veya daha fazla dizinle eşleşecek ve
                  alt dizinler. Desenden sonra bir / gelirse, yalnızca
                  dizinler ve alt dizinler eşleşiyor.

Şimdi, globstar işlemede bir zamanlar bir hata olup olmadığını merak ediyorum, çünkü şimdi basitçe ls **/*.ext doğru sonuçlar alıyorum.

Ne olursa olsun baktım kenorb'un VLC deposunu kullanarak yaptığı analize analizde bazı problemler buldum ve hemen yukarıdaki cevabımda:

findBelirtmek -type fdiğer dosya türlerini (özellikle dizinler) içermediğinden ve lslistelenen komutlar büyük olasılıkla içerdiğinden , komutun çıktısıyla karşılaştırmalar geçersizdir . Ayrıca, listelenen komutlardan biri ls -1 {,**/}*.*- yukarıdaki benimkine dayanıyor gibi görünüyor, yalnızca isimleri verir alt dizinlerde bulunan dosyalar için bir nokta içeren . OP'nin sorusu ve cevabım bir nokta içeriyor, çünkü aranan şey belirli bir uzantıya sahip dosyalar.

Ancak en önemlisi, lskomutu globstar kalıbı ile kullanmanın özel bir sorunu olmasıdır **. Desen Bash tarafından incelenen ağaçtaki tüm dosya adlarına (ve dizin adlarına) genişletildiği için birçok kopya ortaya çıkar. Genişletmeden sonra lskomut her birini listeler birini ve eğer dizin iseler içeriklerini .

Misal:

Mevcut dizinimizde alt dizin Ave içeriği bulunmaktadır:

A
└── AB
    └── ABC
        ├── ABC1
        ├── ABC2
        └── ABCD
            └── ABCD1

Bu ağaçta **"AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1" (7 giriş) olarak genişler . Bunu yaparsanız echo **, elde edeceğiniz kesin çıktı budur ve her giriş bir kez temsil edilir. Ancak , bunu yaparsanız , bu girişlerin her birininls ** bir listesini çıkarır. Yani esasen onu vb. Takip eder , bu yüzden iki kez gösterilir. Ayrıca, her alt dizinin çıktısını birbirinden ayıracak:ls Als A/ABA/ABls

...
<blank line>
directory name:
content-item
content-item

Bu yüzden kullanmak wc -l, sayımı daha da ileri götüren tüm bu boş satırları ve dizin adı bölüm başlıklarını sayar.

Bu, ayrıştırmamanız içinls başka bir neden .

Bu ayrıntılı analizin bir sonucu olarak, bir dosya ağacı üzerinde şu şekilde yineleme dışında hiçbir durumda globstar modelini kullanmamanızı tavsiye ederim:

for entry in **
do
    something "$entry"
done

Son bir karşılaştırma olarak, kullanışlı olduğum bir Bash kaynak deposu kullandım ve şunu yaptım:

shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .

Kullandığım trhiçbir isim boşluk beri burada geçerlidir satırsonlarına boşluk değiştirmek için. Kullandığım sedlider çıkarmak için ./çıktısı, her hattan find. Ben çıktısını sıralanmış findnormal sıralanmamış ve globs Bash'in genişlemesi zaten sıralanır beri. Gördüğünüz gibi, tek çıktı diffgeçerli dizinden .çıktı find. Yaptığımda ls ** | wc -lçıktı neredeyse iki kat fazla satıra sahipti.


5
Ubuntu ve Cygwin'i test ettim ve globstarvarsayılan olarak ayarlandıoff
— Steven Penny 13

12
En iyi cevap! ama bence **/*.extyeterli olmalı. Ayrıca, siz olmadıkça gizli dosyalara sahip olmayacaksınız shopt -s dotglob.
— gniourf_gniourf

2
Devre dışı bırakmak için globstar: shopt -u globstar.
— kenorb

4
@gniourf_gniourf Soru aslında mevcut dizini özellikle eklemeyi istiyor, bu yüzden hayır, **/*.extyeterli olmayacak
— msciwoj

2
@dotnetCarpenter: Bash'in MacOS ile birlikte gelen sürümü, öğrendiğiniz gibi globstar'ı desteklemeyen 3.2'dir. Çift yıldız işareti, tek bir yıldızla aynı şekilde değerlendirilir. Globstar, Bash 4.0'da tanıtıldı.
— sonraki duyuruya kadar duraklatıldı.

13

Bu, geçerli dizindeki tüm dosyaları ve '.ext' ile biten alt dizinlerini yazdıracaktır.

find . -name '*.ext' -print

Bu cevap OP'nin talep ettiği "genişlemeyi" en katı anlamda karşılamasa da, büyük olasılıkla istenen sonucu üretecektir.
— sonraki duyuruya kadar duraklatıldı.

7

**/*.*Tüm dosyaları yinelemeli olarak dahil etmek için: kullanabilirsiniz (etkinleştiren:) shopt -s globstar.

Lütfen diğer varyasyonların testlerini ve nasıl davrandıklarını aşağıda bulabilirsiniz.


Örnek VLC veri havuzu klasöründe 3472 dosya içeren test klasörü:

(Toplam göre sayılan 3472 ait: find . -type f | wc -l)

  • ls -1 **/*.* - 3338 değerini döndürür
  • ls -1 {,**/}*.*- 3341 döndürür ( Dennis tarafından önerildiği gibi )
  • ls -1 {,**/}* - 8265 değerini döndürür
  • ls -1 **/*- gizli dosyalar haricinde 7817 döndürür ( Dennis tarafından önerildiği gibi )
  • ls -1 **/{.[^.],}*- 7869 döndürür ( Dennis tarafından önerildiği gibi )
  • ls -1 {,**/}.?* - 15855 değerini döndürür
  • ls -1 {,**/}.* - 20321 değerini döndürür

Bu nedenle, tüm dosyaları yinelemeli olarak listelemeye en yakın yöntemin, gniourf-gniourf yorumuna**/*.* göre ilk örnek ( ) olduğunu düşünüyorum (dosyaların uygun uzantılara sahip olduğunu veya belirli bir uzantıyı kullandığını varsayarak), çünkü ikinci örnek aşağıdaki gibi birkaç kopya daha veriyor :

$ diff -u <(ls -1 {,**/}*.*) <(ls -1 **/*.*)
--- /dev/fd/63  2015-04-19 15:25:07.000000000 +0100
+++ /dev/fd/62  2015-04-19 15:25:07.000000000 +0100
@@ -1,6 +1,4 @@
 COPYING.LIB
-COPYING.LIB
-Makefile.am
 Makefile.am
@@ -45,7 +43,6 @@
 compat/tdestroy.c
 compat/vasprintf.c
 configure.ac
-configure.ac

ve diğeri daha fazla kopya oluşturur.


Gizli dosyaları dahil etmek için şunu kullanın: shopt -s dotglob(ile devre dışı bırak shopt -u dotglob). mvVeya gibi komutları etkileyebileceğinden rmve yanlışlıkla yanlış dosyaları kaldırabileceğiniz için önerilmez .


Globstar'ın etkin olduğu Mac terminali ve bash üzerinde, yukarıdaki çözümü ( **/*.*) bilgilendirici buldum ve en iyi şekilde çalıştım. Kabul edilen yanıt, üst dizindeki öğelerin yinelenmesine neden oldu. Çalışma "${path}"**/*.*
— modelim

Bunu nullglob ve dotglob gibi diğer seçeneklerle denemek ilginç olurdu
— Wilf

4
$ find . -type f

Bu, geçerli dizindeki tüm dosyaları listeler. Daha sonra -exec kullanarak çıktıda başka bir komut yapabilirsiniz.

$find . -type f -exec grep "foo" {} \;

Bu, "foo" dizesi için bulunan her dosyayı bulacaktır.


Artık 11 yıl sonra, birisinin find . -type fyalnızca geçerli dizine değil, geçerli dizindeki kök ile özyinelemeli olarak geçerli olduğuna işaret etme zamanı gelmiş olabilir .
— Roger Dahl

4

Neden geçerli dizini de dahil etmek için küme ayracı genişletmesini kullanmıyorsunuz?

./{*,**/*}.ext

Ayraç genişletmesi glob genişlemesinden önce gerçekleşir, böylece bash'ın eski sürümleriyle istediğinizi etkili bir şekilde yapabilir ve daha yeni sürümlerde globstar ile maymunluk yapmaktan vazgeçebilirsiniz.

Ayrıca, ./bash'da liderliği glob kalıplarınıza dahil etmek iyi bir uygulama olarak kabul edilir .

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.