Bawiłem się ekspansją i zauważyłem osobliwe zachowanie. Próbowałem zrobić:
echo ./*.txt
I nie miałem żadnego pliku .txt w moim bieżącym katalogu. Otrzymałem wynik:
./*.txt
Jestem tylko ciekawy: dlaczego to dostałem? Spodziewałem się, że nie otrzymam żadnych wyników.
PS: Kiedy miałem .txt
plik, rozszerzenie było poprawnie interpretowane. Innymi słowy, powiedzmy, że miałem plik, smthn.txt
echo faktycznie odbiło się echem current_directory/smthn.txt
.
źródło
shopt -s nullglob
da puste ciągi dla niedopasowanych wzorów ishopt -u nullglob
(ustawienie standardowe) da sam wzór.Gdyby
nullglob
były domyślne, wiele poleceń zachowywałoby się dość nieoczekiwanie, ponieważ (być może niestety) często polecenia traktują sprawę zerowych argumentów nazw plików w jakościowo odmienny sposób niż przypadek jednego lub więcej argumentów nazw plików.Załóżmy, że masz włączoną funkcję
nullglob
(shopt -s nullglob
) i jesteś w katalogu, w którym nie ma pasujących plików*.txt
. Wtedy*.txt
rzeczywiście rozwinie się do zera - nie pustego pola, ale żadnych pól - zgodnie z oczekiwaniami. Ale to przyniosłoby następujące wyniki:ls *.txt
wyświetlałby listę wszystkich plików w bieżącym katalogu (oprócz plików ukrytych), ponieważ dzieje sięls
tak, gdy nie przekaże się żadnych argumentów nazw plików.cat *.txt
czytałby ze standardowego wejścia , ponieważ gdycat
nie ma argumentów nazwy pliku, to tak jakbyś uruchomiłcat -
. Jeśli działa interaktywnie, siedzi i czeka na dane wejściowe. Wiele poleceń zachowuje się w ten sposób.cp *.txt dest/
nie powiedzie się z powodu błęducp: missing destination file operand after 'dest/'
. To nie jest katastrofa, ale jest myląca i zupełnie inna niż cichy sukces, który prawdopodobnie jest pożądany.file *.txt
, i różne inne programy bez specjalnego zachowania w przypadku argumentów zerowej nazwy pliku, nadal nie powiodłyby się z komunikatem o błędzie lub użytkowaniu, gdy żaden nie zostanie przekazany.printf 'Got file: "%s"\n' *.txt
wydrukujeGot file: ""
zamiast niczego.*
,?
i[
które nie są przeznaczone do rozszerzony przez powłokę będzie częściej produkują oczywiście błędne wyniki, ale w sposób, który może być trudny do rozszyfrowania. Na przykład, jeśli żadna nazwa pliku w bieżącym katalogu nie zaczyna się odgedit
, wtedyapt list gedit*
(gdzieapt list 'gedit*'
zamierzano) stałby się sprawiedliwyapt list
i wyświetlałby listę wszystkich dostępnych pakietów.Dobrze więc, że nie dostajesz tego zachowania bez żądania go. Prawdopodobnie najczęstszą praktyczną sytuacją, która jest w rzeczywistości uproszczona,
nullglob
jestfor f in *.txt
. Zobacz także to pytanie (z którym łączy się odpowiedź Siergieja Kolodyazhnyya ).Trudniejsze pytanie brzmi: dlaczego -
failglob
w przypadku błędu rozszerzenia brak globu, który nie pasuje do żadnego pliku - nie jest domyślny w bash. Uważam, że odpowiedź Siergieja Kolodyazhnyya zawiera przyczynę tego, nawet bez bezpośredniego odesłania . Zatrzymywanie nierozwijających się globów bez powodowania błędu ekspansji jest (być może niestety) znormalizowanym zachowaniem, a także zachowaniem tradycyjnym, a zatem oczekiwanym. Chociaż bash nie próbuje być w pełni zgodny z POSIX, chyba że zostanie wywołany z nazwąsh
lub nie prześle--posix
opcji, wiele z jego opcji projektowych, nawet gdy nie jest w trybie POSIX, następuje bezpośrednio po POSIX. Musieli wybrać pewne zachowanie i są wady związane z nieprzestrzeganiem oczekiwań użytkowników.Myślę, że jest to najmniej wpływowy historycznie aspekt tej sprawy, więc zostawiłem to na koniec ... ale warto wspomnieć, że w zachowaniu jest coś dziwnie koncepcyjnego
nullglob
.nullglob
na pierwszy rzut oka wydaje się elegancki, ponieważ pod względem składniowym traktuje przypadek zero pasujących plików nie inaczej niż przypadek jednego, dwóch lub dowolnej innej liczby. Uruchamiane przez nas polecenia, dla których globusy zamieniają się w argumenty, nie traktują ich tak samo, jak opisano powyżej. Ale syntaktycznie wydaje się to co najmniej słuszne, co myślę, że jest motywacją do twojego pytania.A jednak istnieje inna, bardziej subtelna niespójność,
nullglob
która nie rozwiązuje problemu - a która nasila. Przypadek zerowania znaków globowania („symboli wieloznacznych”) jest traktowany zupełnie inaczej niż w przypadku jednej, dwóch lub dowolnej innej liczby. Na przykład,shopt -s nullglob
jeśliab?d?f
nie pasuje do żadnego pliku, jest usuwany; jeśliab?d
nie pasuje do żadnego pliku, jest usuwany; ale jeśliab
nie pasuje do żadnego pliku (tzn. jeśli nie ma pliku o dokładnie takiej nazwieab
), nadal nie jest usuwany. Oczywiście byłoby katastrofą, gdyby został usunięty, ponieważ może nie być przeznaczony do odwoływania się do istniejącego pliku w bieżącym katalogu; może nawet nie odnosić się do pliku. Ale to wciąż eliminuje wszelką nadzieję na całkowitą spójność.Trzy zachowania, które zapewnia bash - domyślne traktowanie globów, które nie pasują do żadnych plików, tak jakby nie były globami, i przekazywanie ich jako nierozwinięte, zachowanie, którego się spodziewałeś po ich traktowaniu (jeśli wybaczysz ten dziwny zwrot frazy) jako oznaczające wszystkie zero plików, które pasują do siebie (
nullglob
), oraz bezpieczne zachowanie polegające na uznaniu ich za błędy (failglob
) - wszystkie reprezentują różne podejścia do dwuznaczności związanej z powłoką, która nie jest w stanie stwierdzić, czy jakieś konkretne słowo ma być Nazwa pliku. Powłoka wykonuje ekspansje bez wiedzy o tym, jak poszczególne polecenia, które wywołujesz, będą traktować ich argumenty.Jest to jeden z wielu przypadków rozdzielenia obaw . W systemach, których projekt jest zgodny z filozofią Uniksa, każda część ma na celu zrobienie jednej rzeczy i wykonanie jej dobrze . Powłoka przetwarza tekst na polecenia i argumenty i wywołuje te polecenia, z których większość jest zewnętrzna względem samej powłoki. Jest to zwykle o wiele ładniejsze i bardziej wszechstronne niż systemy, w których polecenia zewnętrzne są same odpowiedzialne za wykonywanie tych transformacji (jak w przypadku tradycyjnych procesorów poleceń w DOS i Windows). Ale ma to czasem swoje wady.
źródło
failglob
. Dlatego nie może być domyślną wartością, ponieważ nie zawsze była obsługiwana.Głównym powodem jest to, ponieważ jest to zachowanie standardowe określony przez POSIX - średnia, która obejmuje powłoki języka poleceń i wśród innych rzeczy pasujące do wzorca (takich jak muszle
bash
,dash
Shell - domyślnie Ubuntu/bin/sh
iksh
śledzić ten standard). Z sekcji 2.13.3 Wzorce używane do rozszerzenia nazw plików :Ma to oczywiście efekt uboczny - dopasowanie nazwy pliku, które może być dosłownie
*.txt
.nullglob
Opcja wbash
izsh
może pomóc: jeśli ta opcja jest włączona poprzezshopt -s nullglob
(i to nie jest domyślnie włączona, odnoszący się do tej kwestii), a następnie globstar zostanie poszerzona do pustej struny, gdy nie znaleziono żadnych pasujących nazwach.ksh93
ma własny zaawansowany mechanizm dopasowywania wzorów, który zapewnia ten sam efekt~(N)*.txt
Zobacz także Dlaczego nullglob nie jest domyślny?
źródło