Jaka jest różnica między [[$ a == z *]] a [$ a == z *]?

35

Czy jest jakaś różnica między tymi dwoma.

[[ $a == z* ]]

i

[ $a == z* ] 

Czy mogę podać przykład, w którym miałyby różne wyniki?

Ponadto, czym [[ ]]różni się działanie [ ]?

Munish
źródło

Odpowiedzi:

41

Różnica między [[ … ]]i [ … ]jest w większości pokryta za pomocą pojedynczego lub podwójnego wspornika - bash . Co najważniejsze, [[ … ]]jest specjalną składnią, podczas gdy [jest śmiesznie wyglądającą nazwą polecenia. [[ … ]]ma specjalne reguły składni dla tego, co jest w środku,[ … ] nie.

Z dodanym zmarszczeniem znaku wieloznacznego, oto jak [[ $a == z* ]]jest oceniany:

  1. Parsuj polecenie: jest to [[ … ]]konstrukcja warunkowa wokół wyrażenia warunkowego$a == z* .
  2. Analizuj wyrażenie warunkowe: jest to ==operator binarny z operandami $aiz* .
  3. Rozwiń pierwszy operand na wartość zmiennej a .
  4. Oceń ==operatora: sprawdź, czy wartość zmiennej aodpowiada wzorowiz* .
  5. Oceń wyrażenie warunkowe: jego wynik jest wynikiem operatora warunkowego.
  6. Polecenie jest teraz oceniane, jego status to 0, jeśli wyrażenie warunkowe było prawdziwe, i 1, jeśli było fałszywe.

Oto jak [ $a == z* ]jest oceniany:

  1. Przetwarza komendy: to [polecenie z argumentami utworzonych przez ocenę słów $a, ==, z*, ].
  2. Rozwiń $ado wartości zmiennej a.
  3. Przeprowadź dzielenie słów i generowanie nazw plików w parametrach polecenia.
    • Na przykład, jeśli wartość ajest ciąg 6-znakowy foo b*(otrzymane np a='foo b*') i lista plików w aktualnym katalogu jest ( bar, baz, qux, zim, zum), to wynikiem ekspansji jest poniższa lista słów: [, foo, bar, baz, ==, zim, zum, ].
  4. Uruchom polecenie [ z parametrami uzyskanymi w poprzednim kroku.
    • Przy powyższych przykładowych wartości [polecenie skarży się na błąd składniowy i zwraca status 2.

Uwaga: W [[ $a == z* ]]kroku 3 wartość parametru anie jest dzielona na słowa i generowana nazwa pliku, ponieważ występuje w kontekście, w którym oczekiwane jest pojedyncze słowo (lewy argument operatora warunkowego ==). W większości przypadków, jeśli pojedyncze słowo ma sens w tej pozycji, wówczas zmienna interpretacja zachowuje się tak, jak w przypadku podwójnych cudzysłowów. Istnieje jednak wyjątek od tej reguły: w [[ abc == $a ]], jeśli wartość azawiera symbole wieloznaczne, wówczas ajest dopasowywana do wzorca symboli wieloznacznych. Na przykład, jeśli wartość ajest a*wtedy [[ abc == $a ]]jest prawdziwa (bo wieloznaczny *pochodzących z nienotowanego ekspansji $ameczów pochodzących z cytowanego ekspansji nie pasuje ). Wewnątrz* ), podczas gdy [[ abc == "$a" ]]jest fałszywe (bo zwykły znak*$abc[[ … ]] , cudzysłowy nie robią różnicę, z wyjątkiem na prawej stronie operatorów pasujące ciąg ( =, ==, !=i =~).

Gilles „SO- przestań być zły”
źródło
39

[jest aliasem testpolecenia. Unix w wersji 6 miał ifkomendę, ale wersja 7 (1979) została dostarczona z nową powłoką Bourne'a, która miała kilka konstrukcji programowych, w tym konstrukcję if-then-else-elif-fi, a wersja 7 w systemie Unix dodała testpolecenie, które wykonało większość „testy”, które zostały przeprowadzone przez ifpolecenie w starszych wersjach.

[został utworzony alias do testi oba zostały wbudowane w powłokę w systemie Unix III (1981) . Chociaż należy zauważyć, że niektóre warianty Uniksa nie miały [komendy później niż znacznie później ( do wczesnych lat 2000 na niektórych BSD, gdzie shbazuje na powłoce Almquist ( testwbudowane zawsze było zawarte w ashźródle, ale na tych BSD początkowo był wyłączony)).

Zauważ, że testaka [to polecenie do wykonania „testów”, nie ma przypisania, które to polecenie wykonuje, więc nie ma powodu, aby rozróżniać między operatorem przypisania a operatorem równości, więc operator równości jest =. ==jest obsługiwany tylko przez kilka ostatnich implementacji [(i jest tylko aliasem =).

Ponieważ [to nic innego jak polecenie, jest ono analizowane w taki sam sposób jak każde inne polecenie wykonywane przez powłokę.

W szczególności, w twoim przykładzie, $aponieważ nie jest cytowany, zostałby podzielony na kilka słów zgodnie ze zwykłymi regułami podziału słów, a każde słowo podlegałoby generowaniu nazw plików, czyli globbingowi, co skutkowałoby powstaniem możliwie większej liczby słów, a każde z tych słów skutkowało oddzielny argument do [polecenia.

Podobnie z*zostanie rozwinięty do listy nazw plików w bieżącym katalogu, zaczynając od z.

Tak na przykład, jeśli $ajest b* = xi istnieje z1, z2, b1a b2pliki w bieżącym katalogu The [komenda dostanie 9 argumentów: [, b1, b2, =, x, ==, z1, z2i ].

[analizuje argumenty jako wyrażenie warunkowe. Te 9 argumentów nie sumuje się do prawidłowego wyrażenia warunkowego, więc prawdopodobnie zwróci błąd.

[[ ... ]]Konstrukt wprowadzono Korn prawdopodobnie około 1988 roku ksh86a1987 nie ma jej, gdy ksh88miało to od samego początku.

Oprócz ksh (wszystkie implementacje), [[...]]jest również obsługiwany przez bash (od wersji 2.02) i zsh, ale wszystkie trzy implementacje są różne i istnieją różnice między każdą wersją tej samej powłoki, chociaż zmiany są ogólnie kompatybilne wstecz (zauważalnym wyjątkiem jest bash =~operatora, o którym wiadomo, że łamie kilka skryptów po określonej wersji, gdy jego zachowanie się zmieniło). [[...]]nie jest określony przez POSIX, Unix lub Linux (LSB). Został rozważony do włączenia kilka razy, ale nie został uwzględniony, ponieważ jego powszechna funkcjonalność obsługiwana przez główne powłoki jest już objęta [poleceniem i case-in-esackonstrukcją.

Cała [[ ... ]]konstrukcja tworzy polecenie. Oznacza to, że ma status wyjścia (co jest jego najważniejszym zasobem, ponieważ jest wynikiem oceny wyrażenia warunkowego), możesz przesłać go do innego polecenia (chociaż nie byłoby to przydatne) i ogólnie używać go gdziekolwiek byś nie chciał użyj dowolnego innego polecenia (tylko wewnątrz powłoki, ponieważ jest to konstrukcja powłoki), ale nie jest analizowane jak zwykłe proste polecenie. To, co jest w środku, jest analizowane przez powłokę jako wyrażenie warunkowe, a zwykłe zasady podziału słów i generowania nazw plików obowiązują inaczej.

[[ ... ]]wie o tym ==od samego początku i odpowiada =1 . Błąd w ksh (i powoduje zamieszanie i wiele błędów) polega na tym, że =i ==nie są operatorem równości, ale operatorem dopasowywania wzorców (chociaż aspekt dopasowywania można wyłączyć przez cytowanie, ale z niejasnymi regułami, które różnią się w zależności od powłoki).

W powyższym kodzie [[ $a == z* ]]powłoka przeanalizuje to w kilka tokenów w regułach podobnych do zwykłych, rozpozna je jako porównanie dopasowania wzorca, potraktuje z*jako wzorzec pasujący do zawartości azmiennej.

Zasadniczo trudniej jest strzelić sobie w stopę, [[ ... ]]niż w [komendę. Ale kilka zasad takich jak

  • zawsze podawaj zmienne
  • Nigdy nie używać -aalbo -ooperatora (użyć kilku [poleceń oraz &&i || powłoki operatorzy)

Bądź [niezawodny dzięki powłokom POSIX.

[[...]]w różnych powłokach obsługują dodatkowe operatory, takie jak operatory -ntdopasowania wyrażenia regularnego ... ale lista i zachowanie różni się w zależności od powłoki i wersji i wersji.

Więc jeśli nie wiesz, jaką powłokę i jej minimalną wersję będzie kiedykolwiek interpretował twój skrypt, prawdopodobnie bezpieczniej jest trzymać się standardowego [polecenia.


1 Wyjątek: [[...]]został dodany do wersji bash 2.02. Dopóki 2.03nie zostanie zmieniony, [[ x = '?' ]]zwróci prawdę, a [[ x == '?' ]]zwróci fałsz. To znaczy, że cytowanie nie zapobiegło dopasowaniu wzorca podczas korzystania z =operatora w tych wersjach, ale miało to miejsce podczas używania ==.

Stéphane Chazelas
źródło
Świetna informacja. Czy mógłby Pan wyjaśnić, dlaczego „nigdy nie należy używać operatora -a lub -o”?
grebneke
@grebneke, spróbuj [ '!' = foo -o a = a ]się bashna przykład.
Stéphane Chazelas
0

oba są używane do oceny wyrażeń i [[nie będzie działać ze starszą powłoką POSIX-a i [[obsługuje także dopasowanie wzorca i wyrażenia regularne. przykład spróbuj tych

[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"

[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"

harish.venkat
źródło
Zauważ, że powłoka Bourne'a nie jest POSIX, [[...]]obsługuje wyrażenia regularne tylko w niektórych wersjach niektórych powłok, podobnie jak niektóre wersje [obsługują dopasowanie wyrażenia regularnego . Dla arithemtic porównania w tych skorup, że wsparcie [[, wolisz napisać(( n == 0 && y == 0))
Stéphane Chazelas