W większości powłok nullglob
nie 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 nullglob
którego domyślnie jest on wyłączony? Jeśli tak, to z jakiego powodu?
*
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*
?Odpowiedzi:
nullglob
Opcja (BTW tozsh
wynalazek, tylko dodaje lat późniejbash
(2.0
)) nie byłby idealny w wielu przypadkach. Ils
jest dobrym przykładem:Lub jego bardziej prawidłowy odpowiednik:
Włączony
nullglob
działałbyls
bez argumentu, który jest traktowany jakols -- .
(wyświetla bieżący katalog), jeśli żaden plik nie pasuje, co jest prawdopodobnie gorsze niż wywoływaniels
z literałem*.txt
jako argumentem.Miałbyś podobne problemy z większością narzędzi tekstowych:
Będzie szukać
foo
na stdin jeśli nie matxt
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 tofailglob
opcję (ciekawe w tej dyskusji, ponieważ w przeciwieństwie doash
AT&Tksh
lubzsh
,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
lubbash -O failglob
w przypadkach takich jak: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ę:
Możesz uzyskać takie zachowanie za
zsh
pomocąsetopt cshnullglob
bardziej rozsądnego sposobu, aby to zrobić,zsh
używając globu takiego jak:W
zsh
iksh93
możesz również zastosować nullglob dla poszczególnych globów , co jest o wiele zdrowszym podejściem niż modyfikowanie ustawień globalnych: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 jakzsh
globusy używane wfor
,set
lubcount
.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ę takcsh
: 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:
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ólezsh
).źródło
nullglob
wydaje się, że przerywa uzupełnianie tabulacji (naciśnięcie klawisza tab nie robi nic, gdy jest włączone).files=$(shopt -s nullglob;echo *.txt)
xpg_echo
) w zmienne skalarne . Że trzeba cośreadarray -td '' files < <(shopt -s nullglob; printf '%s\0' *.txt)
zbash
4.4 lub powyżej lub(shopt -s nullglob; printf '%s\0' *.txt) | xargs -r0 cmd
z GNUxargs
za to być użyteczne w ogóle z dowolnych nazw plików. Lub, nadal w bash4.4, użyj funkcji pomocnika, która używalocal -
(skopiowana z popiołu 25 lat później) do lokalnego zakresu opcji.