**/*.ext
Eş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?
Yanıtlar:
Bu Bash 4'te çalışacak:
ls -l {,**/}*.ext
Çift yıldız işaretli kürenin çalışması için, globstar
seç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:
find
Belirtmek -type f
diğer dosya türlerini (özellikle dizinler) içermediğinden ve ls
listelenen 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, ls
komutu 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 ls
komut her birini listeler birini ve eğer dizin iseler içeriklerini .
Misal:
Mevcut dizinimizde alt dizin A
ve 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 A
ls A/AB
A/AB
ls
...
<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 tr
hiçbir isim boşluk beri burada geçerlidir satırsonlarına boşluk değiştirmek için. Kullandığım sed
lider çıkarmak için ./
çıktısı, her hattan find
. Ben çıktısını sıralanmış find
normal sıralanmamış ve globs Bash'in genişlemesi zaten sıralanır beri. Gördüğünüz gibi, tek çıktı diff
geçerli dizinden .
çıktı find
. Yaptığımda ls ** | wc -l
çıktı neredeyse iki kat fazla satıra sahipti.
globstar
varsayılan olarak ayarlandıoff
**/*.ext
yeterli olmalı. Ayrıca, siz olmadıkça gizli dosyalara sahip olmayacaksınız shopt -s dotglob
.
globstar
: shopt -u globstar
.
**/*.ext
yeterli olmayacak
Bu, geçerli dizindeki tüm dosyaları ve '.ext' ile biten alt dizinlerini yazdıracaktır.
find . -name '*.ext' -print
**/*.*
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ürls -1 {,**/}*.*
- 3341 döndürür ( Dennis tarafından önerildiği gibi )ls -1 {,**/}*
- 8265 değerini döndürürls -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ürls -1 {,**/}.*
- 20321 değerini döndürürBu 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
). mv
Veya gibi komutları etkileyebileceğinden rm
ve yanlışlıkla yanlış dosyaları kaldırabileceğiniz için önerilmez .
**/*.*
) bilgilendirici buldum ve en iyi şekilde çalıştım. Kabul edilen yanıt, üst dizindeki öğelerin yinelenmesine neden oldu. Çalışma "${path}"**/*.*
$ 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.
find . -type f
yalnızca geçerli dizine değil, geçerli dizindeki kök ile özyinelemeli olarak geçerli olduğuna işaret etme zamanı gelmiş olabilir .
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 .
**/*.ext
. İşe yaradığına emin misin?