Dlaczego wbudowana powłoka to „['i powłoka„ [[”


64

O ile mi wiadomo, [[jest ulepszoną wersją [, ale jestem zdezorientowany, gdy widzę [[jako słowo kluczowe i [jest wyświetlany jako wbudowany.

[root@server ~]# type [
[ is a shell builtin
[root@server ~]# type [[
[[ is a shell keyword

TLDP mówi

Wbudowany może być synonimem polecenia systemowego o tej samej nazwie, ale Bash ponownie go implementuje wewnętrznie. Na przykład polecenie echa Bash nie jest takie samo jak / bin / echo, chociaż ich zachowanie jest prawie identyczne.

i

Słowo kluczowe to słowo zastrzeżone, token lub operator. Słowa kluczowe mają specjalne znaczenie dla powłoki i faktycznie są elementami składni składni powłoki. Jako przykłady, dla, while, do i! są słowami kluczowymi. Podobnie jak wbudowane słowo kluczowe jest na stałe zakodowane w Bash, ale w przeciwieństwie do wbudowanego słowa kluczowego samo w sobie nie jest poleceniem, ale podjednostką konstrukcji polecenia. [2]

Nie powinno to zrobić zarówno [i [[słowa kluczowego? Czy coś tu mi brakuje? Również ten link ponownie potwierdza, że zarówno [i [[powinien należeć do tego samego rodzaju.



9
/ bin / [istnieje na moim komputerze.
Joshua,

2
Jako prosty demonstracji jedną różnicą między tymi dwoma: if "[" $x -eq 3 ]działa zgodnie z oczekiwaniami (bo Bash wygląda polecenia o nazwie [, a ta istnieje), ale if "[[" $x -eq 3 ]]nie nie działa (bo znowu Bash wyszukuje polecenie odpowiedniej nazwy, ale tam nie ma [[Komenda).
Kyle Strand,

1
@Joshua Tak /usr/bin/echo, ale to nie znaczy, że to nie jest wbudowane .
Jonathon Reinhart

Wszystkie biuletyny, które istnieją również zewnętrznie, parsują argumenty, jeśli nie były wbudowane.
Joshua

Odpowiedzi:


80

Różnica między [i [[jest dość fundamentalna.

  • [to polecenie. Jego argumenty są przetwarzane tak samo, jak inne argumenty poleceń. Rozważ na przykład:

    [ -z $name ]

    Powłoka rozszerzy się $namei wykona zarówno podział słów, jak i generowanie nazw plików, tak jak w przypadku każdego innego polecenia.

    Na przykład poniższe działanie zakończy się niepowodzeniem:

    $ name="here and there"
    $ [ -n $name ] && echo not empty
    bash: [: too many arguments

    Aby ta funkcja działała poprawnie, konieczne są cytaty:

    $ [ -n "$name" ] && echo not empty
    not empty
  • [[jest słowem kluczowym powłoki, a jego argumenty są przetwarzane zgodnie ze specjalnymi regułami. Rozważ na przykład:

    [[ -z $name ]]

    Powłoka wzrośnie $name, ale w przeciwieństwie do jakiegokolwiek innego polecenia, wykona ani podział na słowa ani nazwy pliku pokolenia na wynik. Na przykład następujące działania się powiodą pomimo spacji osadzonych w name:

    $ name="here and there"
    $ [[ -n $name ]] && echo not empty
    not empty

Podsumowanie

[ jest poleceniem i podlega tym samym regułom, co wszystkie inne polecenia wykonywane przez powłokę.

Ponieważ [[jest słowem kluczowym, a nie poleceniem, powłoka traktuje go specjalnie i działa na bardzo różnych zasadach.


+1. Dzięki. Czy możesz podać źródło (odniesienie), według jakich reguł działa polecenie i słowo kluczowe?
Tim

@Tim Zasady, na podstawie których działają polecenia, są wyszczególnione w man bash. Zobacz w szczególności sekcje zatytułowane „PROSTE ROZSZERZENIE POLECEŃ” i „WYKONANIE POLECEŃ”. Oprócz [[inne bash słowa kluczowe obejmują if, then, whilei „case”. Nie ma ogólnych zasad dla słów kluczowych: każde słowo kluczowe jest szczególnym przypadkiem. man bash zawiera szczegóły dla każdego.
John1024,

62

W V7 Unix - gdzie debiutowała powłoka Bourne'a - [był nazywany testi istniał tylko jako /bin/test. Więc kod, który napiszesz dzisiaj jako:

if [ "$foo" = "bar" ] ; then ...

napisałbyś zamiast tego jako

if test "$foo" = "bar" ; then ...

Ta druga notacja wciąż istnieje i uważam, że jest bardziej jasne o tym, co się dzieje: wywołujesz komendę o nazwie call test, która ocenia jej argumenty i zwraca kod statusu wyjścia, który ifużywa do podjęcia decyzji, co dalej. To polecenie może być wbudowane w powłokę lub może być programem zewnętrznym.¹

[jako alternatywa dla testpóźniejszych. ² Może to być wbudowany synonim test, ale jest również zapewniony tak jak /bin/[w nowoczesnych systemach dla powłok, które nie mają go jako wbudowanego.

[i testmoże być zaimplementowany przy użyciu tego samego kodu. Jest to przypadek /bin/[, a /bin/testna OS X, gdzie są to twarde linki do tego samego executable.³ W rezultacie realizacja całkowicie ignoruje końcowego znaku ]: to nie wymaga go, jeśli nazwać to jak /bin/[, a nie narzekać jeśli zrobić dostarczyć go do /bin/test.⁴

Żadna z tych historii nie ma wpływu [[, ponieważ nigdy nie istniał pierwotny program o nazwie [[. Istnieje wyłącznie w tych powłokach, które implementują go jako rozszerzenie powłoki POSIX .

Część rozróżnienia między „wbudowanym” a „słowem kluczowym” wynika z tej historii. Odzwierciedla to także fakt, że reguły składniowe dla parsowania [[wyrażeń są różne, jak wskazano w odpowiedzi John1024.


Przypisy:

  1. Patrząc na to w ten sposób, wyjaśnia się, dlaczego należy wstawiać spacje [w skryptach powłoki, w przeciwieństwie do sposobu, w jaki nawiasy i nawiasy działają w większości innych języków programowania. Jeśli parser poleceń powłoki jest dozwolony if["$x"..., będzie również musiał zezwolićiftest"$x"...

  2. Stało się to około 1980 roku. /bin/[Nie istnieje w mojej kopii Ancient Unix V7 z 1979 roku, ani nie man testdokumentuje tego jako aliasu. W analogicznym wpisu strony człowiek mam w kopii pre-release z systemu III podręcznika z 1980 roku, to jest na liście.

  3. ls -i /bin/[ /bin/test

  4. Ale nie licz na to zachowanie. Wbudowana wersja Bash [wymaga zamknięcia ], a jego wbudowana testimplementacja będzie narzekać, jeśli to zrobisz .

  5. Rozróżnienie poleceń wbudowanych i zewnętrznych może mieć również znaczenie z innego powodu: obie implementacje mogą zachowywać się inaczej. Dotyczy to echowielu systemów. Ponieważ istnieje tylko jedna implementacja, słowo kluczowe nie wymaga takiego rozróżnienia.


Dziękuję @ Warren Young, ale dlaczego builtini keywordrozróżnienie między [i [[kiedy oba zapewniają tę samą funkcjonalność (z wyjątkiem faktu, że [[ma więcej funkcji niż [)?
Sree,

2
@sree [[jako słowo kluczowe pozwala bashowi robić rzeczy, które nie są możliwe [- na przykład cytowanie nie jest konieczne dużo czasu, ponieważ powłoka jest świadoma, że ​​jest zmienną. Innymi słowy, przetwarzanie wiersza poleceń ma wpływ na użycie słowa kluczowego, ale nie na użycie wbudowanego - dzieje się to znacznie później.
muru

1
Zauważ, że kod dla powłoki V7 Bourne pokazuje [wbudowane, ale kod jest komentowany.
Stéphane Chazelas,

cdjest wbudowany, ale niczego nie przesłania ( cdnie można go zaimplementować jako programu zewnętrznego).
Paŭlo Ebermann

2
Jest to doskonałe podsumowanie historyczne, ale pomija kluczowy szczegół (IMO), wskazany przez muru powyżej i John1024 w ich odpowiedzi, że utworzenie [[słowa kluczowego pozwala powłoce na użycie specjalnych reguł parsowania dla swoich argumentów. Tak więc, niestety, moje głosowanie idzie do John1024.
Ilmari Karonen,

3

[było pierwotnie tylko zewnętrzną komendą, inną nazwą dla /bin/test. Jednak kilka poleceń, takich jak [i echo, jest używanych tak często w skryptach powłoki, że implementatorzy powłoki postanowili skopiować kod bezpośrednio do samej powłoki, zamiast musieć uruchamiać inny proces za każdym razem, gdy są używane. To zmieniło te polecenia w „wbudowane”, chociaż nadal można wywoływać program zewnętrzny pełną ścieżką.

[[przyszedł znacznie później. Mimo że wbudowane funkcje są implementowane wewnętrznie w powłoce, są one przetwarzane podobnie jak polecenia zewnętrzne. Jak wyjaśniono w odpowiedzi John1024, oznacza to, że zmienne nienotowane otrzymają na nich podział słów, a tokeny lubią >i <są przetwarzane jako przekierowanie We / Wy. To sprawiło, że pisanie skomplikowanych wyrażeń porównawczych było niewygodne. [[został utworzony jako składnia powłoki, aby można go było parsować ideosynchronicznie. [[Zmienne wewnątrz nie dzielą się na słowa <i >mogą być używane jako operatory porównania, =mogą zachowywać się inaczej w zależności od tego, czy następny parametr jest cytowany czy nie, itp. Są to wszystkie udogodnienia, które są [[łatwiejsze w użyciu niż tradycyjne [polecenie / wbudowane.

Nie mogli po prostu przekodować [takiej składni, ponieważ byłaby to niezgodna zmiana w milionach skryptów. Korzystając z nowej [[składni, która wcześniej nie istniała, mogli całkowicie przebudować sposób, w jaki jest ona używana w sposób kompatybilny w górę.

Jest to podobne do ewolucji, która zaowocowała $((...))składnią wyrażeń arytmetycznych, która w większości zastąpiła tradycyjne exprpolecenie.


0

Nowsza [[w bashto optymalizacja z [.

Klasyk [ma jedną dużą wadę, ponieważ jest często używany do trywialnej operacji: za każdym razem odradza się nowy proces:
(Tworzy nową przestrzeń adresową tylko do porównywania 0i 1! Za każdym razem!)

Myślę, że głównym punktem dodania [[było sprawienie, aby ocena wyrażenia wewnątrz [nie była procesem dodatkowym. Ale jak [działa nie można zmienić - byłoby utworzyć wiele nieporozumień i problemów. Tak więc optymalizacja została zaimplementowana pod nową nazwą, w bardziej wydajny sposób, mianowicie z wbudowanym poleceniem powłoki.
Stał się słowem kluczowym w składni powłoki jako efekt uboczny.

W tym momencie [był używany pierwszy, był to właściwy sposób, aby to zrobić za pomocą zewnętrznego procesu.


5
Zauważ, że chociaż [pierwotnie było to polecenie zewnętrzne, zostało dodane jako wbudowane w powłokę dość wcześnie, prawdopodobnie do czasu wydania Unix System III i zdecydowanie przed wydaniem Unix System V. Tak więc „dodatkowy proces” nie był problemem od wieków. Jednak składnia pozostała niezmieniona - traktowano ją jak polecenie zewnętrzne.
Jonathan Leffler,

@JonathanLeffler Och, dziękuję, tęskniłem za [obydwoma - to oznacza pewne zmiany ...
Volker Siegel
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.