Nullglob neden varsayılan değil?


61

Çoğu kabukta nullglobvarsayılan değil. Bu, örneğin, eğer bu komutu çalıştırırsanız,

ls *

boş bir dizinde, boş bir argüman listesi yerine *glob'ı değişmeze doğru genişletir *. Bu davranışı değiştirmenin yolları vardır, böylece *boş bir dizinde daha sezgisel görünen boş bir argüman listesi döndürür.

Öyleyse, nullglobvarsayılan olarak devre dışı bırakılmasının bir nedeni var mı? Eğer öyleyse, bu sebep nedir?


13
Birisi bir zamanlar “hep böyle yaptık” şeklinde dönüşen kötü bir seçim yaptı. Yazılım dünyasında çok yaygın bir fenomen (sadece değil).
PSkocik

4
Asıl sebep, nullglob seçeneğinin o zamanlar mevcut olmamasıydı. Bu nedenle geriye dönük uyumluluğu korumak için varsayılan olarak devre dışı bırakılmalıdır.
PM 2Ring

3
Özellikle boş globdan
StrongBad

4
Bazılarının nullglob'un varsayılan olarak etkinleştirilmesi gerektiğinin açık olması gerektiğini düşündüğü izlenimini edindim. Belli olduğunu sanmıyorum. Komuta çağırma işleminden önce kabuğun içinde meydana gelen genişlemelerin, hiçbir şeye genişlemenin değişmemiş kalan dünyadan daha az sezgisel bir davranış olduğu anlamına gelir.
kojiro

2
@kojiro Kime karşı daha az sezgisel? * NIX kabukları hakkında bilgi sahibi olan herkes *bunun bir küre olduğunu bilir ve mevcut tüm dosyalara genişler ; Boş dizin globlarının değişmeze genişletildiği özel bir durum olması nasıl "sezgisel" *?
Kyle Strand,

Yanıtlar:


78

nullglobSeçeneği (BTW bir olan zshbuluş, yalnızca yıl sonra eklenen bash( 2.0vakaların bir dizi ideal olmaz)). Ve lsiyi bir örnek:

ls *.txt

Veya daha doğru bir eşdeğeri:

ls -- *.txt

nullglobOn ile , hiçbir dosya eşleşmiyorsa (geçerli dizini listele) lsherhangi bir argüman olmadan çalışır ls -- ., muhtemelen argüman olarak lsdeğişmez *.txtolarak çağırmaktan daha kötüdür .

Çoğu metin yardımcı programında benzer sorunlarınız olur:

grep foo *.txt

İçin bakar mısın foohiç olmadığını stdin txtdosyası.

Daha mantıklı bir varsayılan ve csh, tcsh, zsh veya fish 2.3+ (ve erken Unix kabuklarından) biri, eğer dünya uyuşmazsa, komutu tamamen iptal etmektir.

bash(sürüm 3 beri) bir sahiptir failglobaksine beri bu tartışmaya ilginç bunun için bir seçenek ( ashAT & T kshveya zsh, basho) 4.4 değiştirmek olsa (seçenekler için yerel kapsamları desteklemez, bir kaç şey kırıldığında küresel etkinleştirilenler seçeneği bash tamamlama işlevleri gibi).

O csh ve tcsh gelen biraz farklı olduğunu unutmayın zsh, fishya bash -O failglobbenzeri durumlarda:

ls -- *.txt *.html

Komutun iptal edilmesi için bütün dünyaların eşleşmemesi gereken yerde. Örneğin, bir txt dosyası varsa ve html dosyası yoksa, bu olur:

ls -- file.txt

Bunu yapmanın daha mantıklı bir yolu zshile bu davranışı elde edebilirsiniz :setopt cshnullglobzsh

ls -- *.(txt|html)

Gelen zshve ksh93, ayrıca uygulayabilirsiniz nullglob bir genel ayarı değiştirerek çok daha saner yaklaşımdır başına glob temelinde:

files=(*.txt(N))  # zsh
files=(~(N)*.txt) # ksh93

txtKomutu bir hatayla atmak yerine dosya yoksa (ya *.txtda diğer kabukları ile tek bir hazır bilgi argümanı olan bir dizi yapmak) boş bir dizi oluşturur .

fish2.3'ten önceki sürümler, bash -O nullglobbir globun eşleşmediği durumlarda etkileşimli olduğunda bir uyarı verir ancak bir uyarı verir. 2.3 yana, gibi çalışır zshkullanılan Neználkovo haricinde for, setya da count.

Şimdi, tarih notunda, davranış aslında Bourne kabuğu tarafından kırılmıştı . Unix'in önceki sürümlerinde, globbing /etc/globyardımcısı aracılığıyla yapıldı ve bu yardımcı şu şekilde davrandı csh: herhangi bir dosya eşleşmediyse, komutları başarısızlığa uğratmaz ve globları aksi takdirde eşleşmeden kaldırırdı.

Bu yüzden bugün içinde bulunduğumuz durum Bourne kabuğundaki kötü bir karardan kaynaklanıyor.

Bourne kabuğunun (ve C kabuğunun) başka bir yeni Unix özelliği ile geldiğine dikkat edin: çevre. Bu değişken genişleme anlamına geliyordu (öncül sadece $1, $2... konumsal parametrelere sahipti ). Bourne kabuğu ayrıca komut değiştirmeyi de başlattı.

Bourne kabuğunun başka kötü tasarım karar muhtemelen Thompson kabuğu ile geriye dönük uyumluluk için değişkenler ve komut ikame (genişlemesi üzerine globbing (ve bölme) yapılmasıdır echo $1hala çağırmak olacaktır /etc/globhalinde $1ihtiva joker (daha ön-işlemci makro genişleme gibi orada, genişletilmiş değerde olduğu gibi kabuk kodu olarak tekrar ayrıştırıldı)).

Eşleşmeyen globların başarısız olması örneğin:

pattern='a.*b'
grep $pattern file

Komutu başarısız olur ( a.whateverbgeçerli dizinde bazı dosyalar yoksa ). csh(aynı zamanda değişken genişleme üzerine globbing de uygular) bu durumda komutta başarısız olmaz (ve içinde olduğu gibi globbing yapmamak kadar iyi olmasa da orada uyuyan bir hata bırakmaktan daha iyi olacağını iddia ediyorum zsh).


Kullanılabilirlik konusunda başka bir sorun daha var: nullglobsekme tamamlamayı bozuyor (sekme tuşuna basıldığında etkin olan hiçbir şey yapmıyor).
Kyle Strand,

1
Nullglob'u bash ile glob bazında kullanmak mümkündür - sözdizimi zsh kadar zarif olmasa dafiles=$(shopt -s nullglob;echo *.txt)
Jon Nalley

2
(Olası dönüşümü ile birlikte dosya adlarının (boşluk) concatenation depolayan @JonNalley, xpg_echobir içine) sayıl değişkenler. Sen böyle bir şey gerekiyordu readarray -td '' files < <(shopt -s nullglob; printf '%s\0' *.txt)ile bash4.4 veya üzeri veya (shopt -s nullglob; printf '%s\0' *.txt) | xargs -r0 cmdGNU xargsbu hiç keyfi dosya adları ile kullanılabilir olması için. Veya hala bash4.4 ile, local -seçenekler için yerel bir kapsam için (25 yıl sonra külten kopyalanan) kullanan bir yardımcı işlev kullanın .
Stéphane Chazelas
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.