Odpowiedzi:
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:
[[ … ]]
konstrukcja warunkowa wokół wyrażenia warunkowego$a == z*
.==
operator binarny z operandami $a
iz*
.a
.==
operatora: sprawdź, czy wartość zmiennej a
odpowiada wzorowiz*
.Oto jak [ $a == z* ]
jest oceniany:
[
polecenie z argumentami utworzonych przez ocenę słów $a
, ==
, z*
, ]
.$a
do wartości zmiennej a
.a
jest 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
, ]
.[
z parametrami uzyskanymi w poprzednim kroku.
[
polecenie skarży się na błąd składniowy i zwraca status 2.Uwaga: W [[ $a == z* ]]
kroku 3 wartość parametru a
nie 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ść a
zawiera symbole wieloznaczne, wówczas a
jest dopasowywana do wzorca symboli wieloznacznych. Na przykład, jeśli wartość a
jest a*
wtedy [[ abc == $a ]]
jest prawdziwa (bo wieloznaczny *
pochodzących z nienotowanego ekspansji $a
meczów pochodzących z cytowanego ekspansji nie pasuje ). Wewnątrz*
), podczas gdy [[ abc == "$a" ]]
jest fałszywe (bo zwykły znak*
$a
bc
[[ … ]]
, cudzysłowy nie robią różnicę, z wyjątkiem na prawej stronie operatorów pasujące ciąg ( =
, ==
, !=
i =~
).
[
jest aliasem test
polecenia. Unix w wersji 6 miał if
komendę, 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 test
polecenie, które wykonało większość „testy”, które zostały przeprowadzone przez if
polecenie w starszych wersjach.
[
został utworzony alias do test
i 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 sh
bazuje na powłoce Almquist ( test
wbudowane zawsze było zawarte w ash
źródle, ale na tych BSD początkowo był wyłączony)).
Zauważ, że test
aka [
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, $a
ponieważ 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 $a
jest b* = x
i istnieje z1
, z2
, b1
a b2
pliki w bieżącym katalogu The [
komenda dostanie 9 argumentów: [
, b1
, b2
, =
, x
, ==
, z1
, z2
i ]
.
[
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 ksh86a
1987 nie ma jej, gdy ksh88
miał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-esac
konstrukcją.
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 a
zmiennej.
Zasadniczo trudniej jest strzelić sobie w stopę, [[ ... ]]
niż w [
komendę. Ale kilka zasad takich jak
-a
albo -o
operatora (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 -nt
dopasowania 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.03
nie 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 ==
.
[ '!' = foo -o a = a ]
się bash
na przykład.
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"
[[...]]
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))