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.