Dlaczego nullglob nie jest domyślny?


61

W większości powłok nullglobnie jest domyślna. Oznacza to na przykład, jeśli uruchomisz to polecenie

ls *

w pustym katalogu rozwinie *glob do dosłownego *, zamiast do pustej listy argumentów. Istnieją sposoby na zmianę tego zachowania, tak aby *w pustym katalogu zwracana była pusta lista argumentów, co wydawałoby się bardziej intuicyjne.

Czy istnieje więc powód, dla nullglobktórego domyślnie jest on wyłączony? Jeśli tak, to z jakiego powodu?


13
Ktoś kiedyś dokonał złego wyboru, który przerodził się w „zawsze tak robiliśmy”. Bardzo powszechne zjawisko (nie tylko) w świecie oprogramowania.
PSkocik

4
Pierwotny powód jest taki, że wtedy opcja nullglob nie istniała. Aby zachować kompatybilność wsteczną, musi być domyślnie wyłączona.
PM 2,

3
Chociaż nie wspomina konkretnie o zerowym glob, ta historia zawiera trochę historii na temat globbingu: unix.stackexchange.com/a/136409/22724
StrongBad

4
Mam wrażenie, że niektórzy sądzą, że powinno być oczywiste, że nullglob powinien być domyślnie włączony. Nie sądzę, że to oczywiste. To, że rozwinięcia mają miejsce w powłoce przed wywołaniem polecenia, oznacza, że ​​rozwijanie do niczego jest mniej intuicyjnym zachowaniem niż glob niezmieniony.
kojiro

2
@kojiro Dla kogo mniej intuicyjny? Każdy, kto zna się na powłokach * NIX, wie, że *jest to glob i rozszerza się na wszystkie istniejące pliki; jak to jest „intuicyjne”, gdy istnieje specjalny przypadek, w którym puste globusy katalogów są „rozszerzane” do literału *?
Kyle Strand,

Odpowiedzi:


78

nullglobOpcja (BTW to zshwynalazek, tylko dodaje lat później bash( 2.0)) nie byłby idealny w wielu przypadkach. I lsjest dobrym przykładem:

ls *.txt

Lub jego bardziej prawidłowy odpowiednik:

ls -- *.txt

Włączony nullglobdziałałby lsbez argumentu, który jest traktowany jako ls -- .(wyświetla bieżący katalog), jeśli żaden plik nie pasuje, co jest prawdopodobnie gorsze niż wywoływanie lsz literałem *.txtjako argumentem.

Miałbyś podobne problemy z większością narzędzi tekstowych:

grep foo *.txt

Będzie szukać foona stdin jeśli nie ma txtplików.

Bardziej sensownym ustawieniem domyślnym, a csh, tcsh, zsh lub fish 2.3+ (i wczesnych powłok uniksowych) jest całkowite anulowanie polecenia, jeśli glob nie pasuje.

bash(od wersji 3) ma na to failglobopcję (ciekawe w tej dyskusji, ponieważ w przeciwieństwie do ashAT&T kshlub zsh, bashnie obsługuje lokalnych zasięgów opcji (choć ma to zmienić w 4.4), ta opcja, gdy jest włączona globalnie, psuje kilka rzeczy jak funkcje kończące bash).

Zauważ, że csh i tcsh są nieznacznie różni się od zsh, fishlub bash -O failglobw przypadkach takich jak:

ls -- *.txt *.html

Gdzie potrzebujesz, aby wszystkie globusy się nie zgadzały, aby polecenie zostało anulowane. Na przykład, jeśli istnieje jeden plik txt i nie ma pliku html, staje się:

ls -- file.txt

Możesz uzyskać takie zachowanie za zshpomocą setopt cshnullglobbardziej rozsądnego sposobu, aby to zrobić, zshużywając globu takiego jak:

ls -- *.(txt|html)

W zshi ksh93możesz również zastosować nullglob dla poszczególnych globów , co jest o wiele zdrowszym podejściem niż modyfikowanie ustawień globalnych:

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

utworzyłby pustą tablicę, jeśli nie ma txtpliku, zamiast błędu polecenia (lub uczynienia go tablicą z jednym *.txtdosłownym argumentem z innymi powłokami).

Wersje fishwcześniejsze niż 2.3 działałyby jak, bash -O nullglobale dają ostrzeżenie, gdy są interaktywne, gdy glob nie pasuje. Od wersji 2.3 działa podobnie jak zshglobusy używane w for, setlub count.

Teraz, zgodnie z notatką historyczną, zachowanie zostało przerwane przez powłokę Bourne'a. We wcześniejszych wersjach Uniksa globowanie odbywało się za pomocą /etc/globpomocnika, który zachowywał się tak csh: nie wykonałby polecenia, jeśli żaden z globów nie pasowałby do żadnego pliku i nie usunąłby globów bez dopasowania.

Tak więc obecna sytuacja wynika z złej decyzji podjętej w powłoce Bourne'a.

Zauważ, że powłoka Bourne'a (i powłoka C) została dostarczona z inną nową funkcją uniksową: środowiskiem. Oznaczało to, że ekspansja zmienna (tylko jego poprzednik miał $1, $2... Parametry pozycyjne). Powłoka Bourne'a wprowadziła także zastępowanie poleceń.

Inną kiepską decyzją projektową powłoki Bourne'a było wykonanie globowania (i podziału) po rozwinięciu zmiennych i podstawianiu poleceń (być może dla wstecznej kompatybilności z powłoką Thompson, gdzie echo $1nadal wywoływałby się, /etc/globgdyby $1zawierał symbole wieloznaczne (bardziej przypominało to ekspansję makroprocesora przedprocesorowego) tam, jak w rozwiniętej wartości, został ponownie przeanalizowany jako kod powłoki)).

Niepowodzenie globów, które nie pasują, oznaczałoby na przykład, że:

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

nie powiedzie się polecenie (chyba że a.whateverbw bieżącym katalogu są jakieś pliki). csh(który wykonuje również globowanie po rozszerzeniu zmiennej) nie wykonuje polecenia w tym przypadku (i argumentowałbym, że jest to lepsze niż pozostawienie uśpionego błędu, nawet jeśli nie jest tak dobre, jak nie wykonywanie globowania w ogóle zsh).


Jest jeszcze jeden problem z użytecznością: nullglobwydaje się, że przerywa uzupełnianie tabulacji (naciśnięcie klawisza tab nie robi nic, gdy jest włączone).
Kyle Strand,

1
Jest to możliwe do wykorzystania nullglob na jednej glob zasadach z bash - choć składnia nie jest tak elegancki jak zshfiles=$(shopt -s nullglob;echo *.txt)
Jon Nalley

2
@JonNalley, który przechowuje konkatenację (ze spacją) nazw plików (z możliwą transformacją za pomocą xpg_echo) w zmienne skalarne . Że trzeba coś readarray -td '' files < <(shopt -s nullglob; printf '%s\0' *.txt)z bash4.4 lub powyżej lub (shopt -s nullglob; printf '%s\0' *.txt) | xargs -r0 cmdz GNU xargsza to być użyteczne w ogóle z dowolnych nazw plików. Lub, nadal w bash4.4, użyj funkcji pomocnika, która używa local -(skopiowana z popiołu 25 lat później) do lokalnego zakresu opcji.
Stéphane Chazelas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.