Bash globbing'in tarihi


11

Bash'in "zonklama" ve düzenli ifadelerin aynı olmamasının tarihsel bir nedeni var mı? Örneğin, Bash'te [1-2]*1 veya 2 ile başlayan herhangi bir şeyle ve ardından başka bir şeyle eşleştiğine inanıyorum, normal bir ifade olarak [1-2]*sadece 1s ve 2s'lik bir diziyle eşleşir. Bash komut dosyam ve REGEX foo'mun her ikisi de oldukça zayıf ve bu farklılıklarla ilişkili problemlerle karşılaşıyorum ve bu da beni neden farklı hissettiklerini merak ediyordu.


3
rm -- ^[^.].*\.txt$Bunun yerine yapmayı düşünür müsünüz rm -- *.txt?
Stéphane Chazelas

1
Çok da Q yılların LWN gelen bu thread değinilmiş: lwn.net/Articles/96687
slm

Dosya adlarında çalışan ve normal ifade alan komutlar vardır. Örneğin dosyaları bulmak find . -regex ".*\.txt$" | xargs rm --veya renameyeniden adlandırmak sediçin (dosya adları içindir), bazı sistemlerin farklı olmasına dikkat edin rename.
ctrl-alt-delor

@richard, ^[^.].*\.txt$nokta dosyalarının yoksayılmasını hesaba katmam gerekti . -regexBir GNU uzantısı olduğuna dikkat edin , ksh93 veya zsh gibi bazı mermiler ksh93 -c 'echo ~(E:^[^.].*\.txt$)'
globlarına normal ifadeleri

2
Bu bash, mevcut uygulamaları çok dikkatli bir şekilde takip ederken, uzlaşmaz uyumsuz değişikliklerden ve uzantılardan kaçınmak en büyük güçlerinden biridir.
ormaaj

Yanıtlar:


12

bashbaşlangıçta 80'lerin sonunda kshcsh / tcsh'ın bazı etkileşimli özellikleri ile kısmi bir klonu olarak tasarlandı .

Globbingin kökenleri, üzerine inşa ettiği önceki mermilerde bulunmalıdır.

kshkendisi Bourne kabuğunun bir uzantısıdır. Bourne kabuğunun kendisi (ilk olarak 1979'da Unix V7'de piyasaya sürüldü) sıfırdan temiz bir uygulamaydı, ancak Thompson kabuğundan (V1 -> V6'nın kabuğu) tamamen ayrılmadı ve Mashey kabuğundan özellikler içeriyordu.

Özellikle, komut argümanlar hala boşlukları ile ayrıldı |şimdi yeni boru operatör oldu ama ^hala bir alternatif olarak desteklenmiştir (ve aynı zamanda yapmanız açıklıyor [!a-z]değil [^a-z]), $1yine bir senaryoya ilk argüman oldu ve ters bölü hala kaçış karakterdi . Regexp operatörlerinin ( ^\|$) birçoğunun kabukta kendilerine özgü bir anlamı vardır.

Thompson kabuğu, globbing için harici bir faydaya dayanıyordu. Ne zaman shtırnaksız bulundu *, [ya da ?komuta s, içinden komutunu çalıştırın olur glob.

rm *.txt

Glob'u şu şekilde çalıştırır:

["glob", "rm", "*.txt"]

glob da rmbu kalıpla eşleşen dosyaların listesiyle çalışır .

grep a.\*b *.txt

şöyle çalışır glob:

["glob", "grep", "a.\252b", "*.txt"]

*Yukarıdaki önlenmesi, yani karaktere 8 bit ayarlayarak sözleri kaydedildi globjoker olarak ele alıp gelen. globaramadan önce o biti kaldıracaktır grep.

Regexps ile eşdeğerini yapmak için şu olurdu:

regexp rm '\.txt$'

Veya:

regexp rm '^[^.].*\.txt$'

nokta dosyalarını hariç tutmak için.

Kabuk özel karakterleri olarak ikiye katlandıkça operatörlerden kaçma ihtiyacı ., dosya adlarında yaygın olan bir normal ifade operatörü olması, dosya adlarını eşleştirmeyi ve yeni başlayanlar için karmaşık olmayı çok uygun hale getirmez. Çoğu durumda, ihtiyacınız olan tek şey bir ( ) veya herhangi bir sayıda ( ) karakterin yerini alabilen joker karakterlerdir.?*

Şimdi, farklı mermiler farklı globlama operatörleri ekledi. Günümüzde, ksh ve zsh glob'ları (ve bir dereceye kadar bash -O extglobksh glob'larının bir alt kümesini uygulayan) fonksiyonel olarak dosya adları ve mevcut kabuk sözdizimi ile daha az kullanışsız bir sözdizimiyle normal ifadelere eşdeğerdir. Örneğin, zsh(genişletilmişglob uzantısıyla) içinde şunları yapabilirsiniz:

echo a#.txt

ve aardından gelen dizilerden oluşan dosya adlarını eşleştirmek istiyorsanız (olası değil) .txt. Daha kolay echo (^a*\.txt$)(burada parantezleri, regex operatörlerini, kabukların onunla başa çıkabileceği tek yönlü olabilecek kabuk operatörlerinden izole etmenin bir yolu olarak kullanmak).

echo (foo|bar|<1-20>).(#i)mpg

Temel adı foo, bar veya ondalık sayı 1'den 20'ye kadar olan mpg dosyaları (büyük / küçük harf duyarlı) için ...

ksh93şimdi gloge'lerine regexps (temel, genişletilmiş, perl benzeri veya "artırılmış") ekleyebilir (oldukça buggy olmasına rağmen) ve hatta glob ve regexp ( printf %R, printf %P) arasında dönüştürme aracı sağlar :

echo ~(Ei:.*\.txt)

ile dosyaları txt maça (non-gizli) E , düzenli ifadeler Xtended küçük harf i nsensitively.


Harika yazı! Aslında ~(opt:pat)büyük harfli seçeneklerden hiçbirini kullanamazsınız . Belki print -r -- ~(Ei).*\.txt$. Deseni içine koymak, bir desenin bir kısmı için bir seçeneği açıp kapatmak zorunda kalmamak için yararlı gibi görünmektedir. Garip bir şekilde, aynı glob içinde birden çok desen dilini karıştırabilir ve eşleştirebilirsiniz. ~(Ki)*.~(E)txt$eşdeğerdir. (Sonunda her şey normal regex'e dönüştürülür ve dahili olarak libast'ın regex motoruna geçer).
ormaaj

@ormaaj, ksh93 ~(Ei:.*\.txt)o + gibi 15 yaşındaki sürümlerle bile benim için çalışıyor.
Stéphane Chazelas

Kaydedilmiş test ikili dosyalarımdan biriyle de çalışır (2014-12-24), ancak bununla ilgili sorunlarla karşılaştığımı hatırlıyorum. Ksh hala ticari olarak geliştirildiğinde işler her zaman rasgele kırıldı ve her versiyon arasında tekrar sabitlendi. Desen eşleme kodunun kırılgan alanlardan biri olduğunu hatırlıyorum.
ormaaj

@ormaaj, biri arasında farklı ~(E)xve ~(E:x)ikincisinin sabitlenmiş olması ( xyalnızca önceki herhangi bir şeyle eşleştiğinde eşleşir x), karşılaştığınız sorun olabilir ( ~(-lr)~(E:x)sabitlemeyi kaldırmak için kullanın , ~(E-lr:x)yapmaz). Her durumda, son sürümde bile oldukça buggy olduğunu kabul ediyorum.
Stéphane Chazelas

9

1956'da Kleene tarafından düzenli diller tanıtıldı . Seminal gazetede düzenli ifadeler için tam bir modern gösterim yoktu, ancak A*“herhangi bir sayıda tekrar” anlamına gelen “ Kleen star” ı tanıttı A. Önümüzdeki on yılda, özellikle .keyfi bir karakter ve bir ?önceki karakterin isteğe bağlı olduğu anlamına gelmek üzere , az çok standart gösterimler ortaya çıktı .

Bash'ın globbing notasyonu , 1971'de Unix v1'de sunulan globkomuttan kaynaklanır . O zaman globbing ayrı bir program tarafından gerçekleştirildi; daha sonra kabuğa taşındı. Erken komut, "herhangi bir karakter" ve "herhangi bir karakter dizisi" anlamına gelmelidir. Karakterlerin neden seçildiğini bilmiyorum; oldukça sezgiseldir ve düzenli ifadelerden ilham almış olabilir.glob?*?*

Globbing'in düzenli ifadeler kadar genel olması amaçlanmamıştı ve düzenli ifadeler o zamanlar çok yaygın değildi, bu yüzden kavramları birleştirmek için bir çağrı yoktu. Başından beri, ile, sözdizimsel uyumsuzluklar vardı ?, .ve *dosya adı desenlerinde ve normal ifadelerde farklı şeyler anlamına gelir.

Bash gibi modern mermiler glob kalıpları üzerinde genişler, ancak geriye dönük uyumluluğu koruyan kademeli bir evrimdi. Ksh88 (1988 versiyonu Korn kabuk :) her zamanki normal ifadeler olarak aynı sözdizimi olamazdı ama şiddetle esinlenerek kabuk kalıpları için uzatılmış sözdizimi, tanıtılan *(PATTERN)tekrarları herhangi bir sayıda anlamında PATTERN, @(PATTERN1|PATTERN2)yani “için PATTERN1veya PATTERN2” vb.

Bash'ın (2.02'den beri) modern sürümleri, shopt -s extglobilk önce yayınlarsanız ksh88'in genişletilmiş desenlerini destekler .


Bash extglobları hiç desteklemedi mi? Bash, zsh ve {pd, m} ksh, bildiğim kadarıyla, ilk günlerden beri ksh88 kılavuzunda belgelendiği şekliyle aynı küreleri destekledi. Ksh'ın bugüne kadar "genişletilmiş" glob miktar belirleyicilerini devre dışı bırakma seçeneği bile yok ve ksh93, ksh88'in ötesinde herhangi bir uzantıya sahip olan tek grup.
ormaaj

2
@ormaaj Ksh88 genişletilmiş globlar ve extglobseçenek 1998'de bir yerlerde bash 2.02'de tanıtıldı. Zsh ksh_glob, aynı zamanda 3.1 serisinde satın aldı . Zsh, kendine özgü birçok globbing uzantısına sahiptir (bazıları extended_globseçeneği gerektirir ).
Gilles 'SO- kötü olmayı kes

Anlıyorum. Bu yüzden aslında bir seçeneğe olan ihtiyacı haklı çıkarmak için geç kalmıştı. (Bence varsayılan kapalı olmak bugünlerde oldukça anlamsız ama ilginç.)
ormaaj

1
@ormaaj, bashaksine ksh, extglob değişkeninin bash değerini POSIX ile uyumlu hale getirmez, çünkü değişkenlerde devre dışı bırakılmaz. İçinde ksh, var='@(*)'; echo $vargeçerli dizinde POSIX'in gerektirdiği gibi @(biten ve biten tüm dosya adlarına genişlerken, tüm dosyalara genişler. (yine de, burada bash davranışı daha mantıklı olabilir (ve değişkenlerde kalıplar olmasını istediğinizde ksh davranışı oldukça acıdır)). Bu glob sözdizimi bu yüzden çok garip (POSIX / Bourne uyumluluğu). Zsh genişletilmiş globlarla karşılaştırın. )bash -O extglob
Stéphane Chazelas

@ StéphaneChazelas Hepsi doğru ve ksh'ın bu konuda ne kadar akıllı olduğunu seviyorum. POSIX ile kısıtlı olmadıkça nadiren oyuna girer. IFS'yi boşaltmanız gerektiğinden, her yerde parantez genişlemesini devre dışı bırakmanız gerektiğinden, sözcük ayırma için neredeyse her kullanımın yerini ve değişkenlerde kalıpları aşırı derecede rahatsız edici bir şekilde saklamak zaten. Depolanmış kalıplarla tamamen güvende olmak hala imkansız. Örneğin bu eski kaçış sorunu hiçbir zaman gerçekten çözülmedi.
ormaaj

1

Tarihsel neden: EVET. Referans:
http://en.wikipedia.org/wiki/Glob_(programming)#Origin

Sadece ayrılığı göstermek için, iyi ve kolay bir örnek: a*

  • kabuk globbing: anlamı, ilk karakter ave sonra ne olursa olsun (a, ab, abca ...)
  • regex: anlamı, karakterin sıfır veya daha fazla tekrarı a(a, aa, aaa ...)

Bu anlam farklılığının yeni kullanıcılar için çok kafa karıştırıcı olduğunu kolayca kabul ediyorum.

Globbing'in yeni gelenler için kavranması daha kolaydır, ancak daha az güçlü bir yapıdır.

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.