Czy ktoś mógłby wyjaśnić różnicę pomiędzy =, ==oraz -eqw skryptów powłoki?
Czy jest jakaś różnica między poniższymi?
[ $a = $b ]
[ $a == $b ]
[ $a -eq $b ]
Czy to po prostu to =i ==są używane tylko wtedy, gdy zmienne zawierają liczby?
Czy ktoś mógłby wyjaśnić różnicę pomiędzy =, ==oraz -eqw skryptów powłoki?
Czy jest jakaś różnica między poniższymi?
[ $a = $b ]
[ $a == $b ]
[ $a -eq $b ]
Czy to po prostu to =i ==są używane tylko wtedy, gdy zmienne zawierają liczby?
Odpowiedzi:
Jest na odwrót: =i ==dotyczy porównań ciągów, -eqdotyczy liczb. -eqjest w tej samej rodziny jako -lt, -le, -gt, -ge, i -ne, jeśli to pomaga zapamiętać, który jest który.
==Nawiasem mówiąc, jest bashizmem. Lepiej jest użyć POSIX =. W bashu te dwa są równoważne, aw zwykłym sh =jest jedynym gwarantowanym działaniem.
$ a=foo
$ [ "$a" = foo ]; echo "$?" # POSIX sh
0
$ [ "$a" == foo ]; echo "$?" # bash specific
0
$ [ "$a" -eq foo ]; echo "$?" # wrong
-bash: [: foo: integer expression expected
2
(Uwaga dodatkowa: zacytuj te rozszerzenia zmiennych! Nie pomijaj powyższych podwójnych cudzysłowów).
Jeśli piszesz #!/bin/bashscenariusz to polecam używając [[zamiast . Podwojona forma ma więcej funkcji, bardziej naturalną składnię i mniej problemów, które mogą Cię zaskoczyć. Podwójne cudzysłowy nie są już wymagane $a, na przykład:
$ [[ $a == foo ]]; echo "$?" # bash specific
0
Zobacz też:
[[ $var = $pattern ]], jeśli chcesz, co w przeciwnym razie być interpretowane jako wzorzec fnmatch zamiast być interpretowane jako dosłownego łańcucha. Ciąg foonie ma interpretacji nieliteralnej, dzięki czemu pozostawienie cudzysłowów jest całkowicie bezpieczne; tylko wtedy, gdy OP chciałby dopasować, powiedzmy, foo*(z gwiazdką jako dosłowną, nie oznaczającą niczego, co może wystąpić po ciągu foo), potrzebne byłyby cudzysłowy lub znaki specjalne.
[[niecytowanych rozszerzeń wewnątrz bycia bashizmem (wskazujący, że był to jedyny powód, dla którego nie dałeś odpowiedzi +1).
[ ... ]i podwójny znak równości ==. : - /
Zależy to od Konstrukcji Testowej wokół operatora. Dostępne opcje to podwójne nawiasy, podwójne nawiasy klamrowe, pojedyncze nawiasy klamrowe lub test
Jeśli używasz ((...)) , testujesz arytmetyczną wartość równą ==jak w C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Uwaga: 0oznacza truew sensie uniksowym, a wartość różna od zera oznacza niepowodzenie testu)
Użycie -eqwewnątrz podwójnego nawiasu jest błędem składniowym.
Jeśli używasz [...] (lub pojedynczego nawiasu klamrowego) lub [[...]] (lub podwójnego nawiasu klamrowego), lub testmożesz użyć jednego z -eq, -ne, -lt, -le, -gt lub -ge jako porównanie arytmetyczne .
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
==Wewnątrz pojedynczymi lub podwójnymi szelkami (lub testpoleceń) jest jednym z operatorów porównania ciąg :
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
Jako operator łańcuchowy =jest równoważny ==i zwraca uwagę na białe znaki wokół =lub ==wymagane.
Chociaż możesz to zrobić [[ 1 == 1 ]]lub [[ $(( 1+1 )) == 2 ]]testuje równość ciągów - nie równość arytmetyczną.
Więc -eqdaje wynik prawdopodobnie oczekiwany, że wartość całkowita 1+1jest równa, 2mimo że RH jest łańcuchem i ma spację na końcu:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
Podczas gdy ciągowe porównanie tego samego zbiera końcową spację i dlatego porównanie ciągów kończy się niepowodzeniem:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
A błędne porównanie ciągów może dać kompletną złą odpowiedź. „10” jest leksykograficznie mniejsze niż „2”, więc porównanie ciągów zwraca truelub 0. Tak wielu gryzie ten błąd:
$ [[ 10 < 2 ]]; echo $?
0
vs poprawny test dla 10 jest arytmetycznie mniejszych niż 2:
$ [[ 10 -lt 2 ]]; echo $?
1
W komentarzach pojawia się kwestia technicznego powodu używania liczby całkowitej -eqw łańcuchach zwraca True dla łańcuchów, które nie są takie same:
$ [[ "yes" -eq "no" ]]; echo $?
0
Powodem jest to, że Bash nie ma typu . -eqPowoduje struny należy interpretować jako liczby całkowite , jeśli to możliwe , w tym konwersji bazy:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
A 0jeśli Bash myśli, że to tylko ciąg:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
Więc [[ "yes" -eq "no" ]]jest równoważne[[ 0 -eq 0 ]]
Ostatnia uwaga: Wiele rozszerzeń Konstrukcji Testowych specyficznych dla Bash nie jest POSIX-owych i dlatego nie powiedzie się w innych powłokach. Inne powłoki generalnie nie obsługują [[...]]i ((...))lub== .
[[ "yes" -eq "no" ]]powrocie prawda. W jaki sposób bash przekształca te ciągi w wartości całkowite, które można porównać? ;-)
[[ "yes" -eq "no" ]]jest równoważne [[ "yes" -eq 0 ]] lub [[ "yes" -eq "any_noninteger_string" ]]- All True. Te -eqsiły całkowitych porównanie. "yes"Jest interpretowane jako liczba 0; porównanie ma wartość Prawda, jeśli drugą liczbą całkowitą jest albo, 0albo wynikiem ciągu jest 0.
==w próbkach kodu i tylko wzmianka (przenośna, standaryzowana) =poniżej.
==jest aliasem specyficznym dla basha dla =i wykonuje porównanie łańcuchowe (leksykalne) zamiast porównania numerycznego. eqbędąc oczywiście porównaniem numerycznym.
Wreszcie, zazwyczaj wolę korzystać z formularza if [ "$a" == "$b" ]
==tutaj jest złą formą, ponieważ =określa tylko POSIX.
==umieść go między [[a ]]. (I upewnij się, że pierwsza linia twojego skryptu wskazuje na użycie /bin/bash.)
Chłopaki: Kilka odpowiedzi zawiera niebezpieczne przykłady. Przykład OP [ $a == $b ]wykorzystywał konkretnie niecytowane podstawianie zmiennych (stan na październik 2017). Bo [...]to jest bezpieczne dla równości łańcuchów.
Ale jeśli masz zamiar wyliczyć alternatywy, takie jak [[...]], musisz również poinformować, że należy zacytować prawą stronę. Jeśli nie jest cytowany, jest to dopasowanie do wzorca! (Ze strony podręcznika bash: "Dowolna część wzorca może być cytowana w cudzysłowie, aby wymusić dopasowanie jako łańcuch.").
Tutaj, w bash, dwie instrukcje dające „tak” są dopasowywaniem do wzorca, pozostałe trzy to równość ciągów:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
[ "$lht" = "$rht" ] z cudzysłowami, aby były wiarygodne nawet dla równości. Jeśli masz plik utworzony za pomocą touch 'Afoo -o AB', [ $lft = $rht ]zwróci wartość true, nawet jeśli nazwa pliku nie jest identyczna z AB.
[[jako całość to ksh-izm z lat 80., który został przyjęty przez bash (i wiele innych powłok). O to właśnie chodzi - jeśli[[w ogóle masz, możesz bezpiecznie założyć, że wszystkie rozszerzenia ksh zaimplementowane wokół niego (fnmatch()dopasowywanie wzorców -styl, wyrażenia regularne ERE z=~i tak, tłumienie dzielenia łańcuchów i globowania systemu plików) będą dostępny. Ponieważ[[jest to składnia inna niż POSIX w całości, nie ma dodatkowej utraty przenośności przy założeniu, że funkcje, z którymi się urodził, będą dostępne.