nullglob
Opcja (BTW to zsh
wynalazek, tylko dodaje lat później bash
( 2.0
)) nie byłby idealny w wielu przypadkach. I ls
jest dobrym przykładem:
ls *.txt
Lub jego bardziej prawidłowy odpowiednik:
ls -- *.txt
Włączony nullglob
działałby ls
bez 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 ls
z literałem *.txt
jako argumentem.
Miałbyś podobne problemy z większością narzędzi tekstowych:
grep foo *.txt
Będzie szukać foo
na stdin jeśli nie ma txt
plikó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 failglob
opcję (ciekawe w tej dyskusji, ponieważ w przeciwieństwie do ash
AT&T ksh
lub zsh
, bash
nie 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
, fish
lub bash -O failglob
w 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 zsh
pomocą setopt cshnullglob
bardziej rozsądnego sposobu, aby to zrobić, zsh
używając globu takiego jak:
ls -- *.(txt|html)
W zsh
i ksh93
moż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 txt
pliku, zamiast błędu polecenia (lub uczynienia go tablicą z jednym *.txt
dosłownym argumentem z innymi powłokami).
Wersje fish
wcześniejsze niż 2.3 działałyby jak, bash -O nullglob
ale dają ostrzeżenie, gdy są interaktywne, gdy glob nie pasuje. Od wersji 2.3 działa podobnie jak zsh
globusy używane w for
, set
lub 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/glob
pomocnika, 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 $1
nadal wywoływałby się, /etc/glob
gdyby $1
zawierał 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.whateverb
w 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
).