Jaka jest różnica między pojedynczymi i podwójnymi znakami równości (=) w porównaniach powłoki?

28

Przeczytaj, że do porównywania napisów w środku ifmusimy użyć podwójnych nawiasów kwadratowych. Niektóre książki mówią, że porównania można dokonać =. Ale to też działa ==.

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi

Czy jest jakaś różnica pomiędzy =i ==w porównaniu?

użytkownik3539
źródło
4
Czy jest gdzieś tutaj pytanie? Jeśli tak, nie widzę tego. =jest dla [. ==jest dla [[.
Chris Down
@ChrisDown To absolutnie nieprawda.
xdavidliu
@xdavidliu Chcesz opracować? To na pewno jest prawdziwe zgodnie z POSIX, który nie ma zrozumienia ==, dlatego należy używać =(równość) z [i ==(dopasowywanie wzorców, które są ze semantyki cytując-aware) z [[. Zobacz help testvs help [[.
Chris Down
@ChrisDown może nie rozumiem, co oznacza „jest za”. Jeśli „jest dla” oznacza, że ​​„działa tylko z”, to komentarz nie jest prawdziwy, ponieważ na [ foo == foo ] && echo foopewno drukuje foo, wskazując, że ==działa z [. Jednakże, jeśli przez „jest dla” masz na myśli, że ”miał być używany z„, to mam mniejszy sprzeciw.
xdavidliu
@xdavidliu „jest” w konkretnym przypadku, o którym wspominasz, oznacza „jest zdefiniowany przez POSIX”. Tylko dlatego, że bash akceptuje to jako wygodę, nie oznacza to, że jest zalecane - jeśli i tak unikasz przenośności, po prostu użyj [[w pierwszej kolejności, która ma znacznie bardziej zróżnicowane rozumienie tokenizacji, dzielenia słów itp.
Chris Down

Odpowiedzi:

28

[[ $a == $b ]]to nie porównanie, to dopasowanie wzorca. Potrzebujesz [[ $a == "$b" ]]porównania równości między bajtami. =jest taki sam jak ==w każdej powłoce, która obsługuje [[...]](wprowadzona przez ksh).

[[...]]nie jest standardową shskładnią. [ Komenda jest standardem, a średnia porównanie operator nie ma =(choć niektóre [implementacje również rozpoznać ==).

Podobnie jak w każdym argumencie dowolnego polecenia, zmienne muszą być cytowane, więc:

[ "$a" = "$b" ]

Standardowo shdopasowywanie wzorców odbywa się za pomocą case:

case $a in
  ($b) ...
esac

Dla kompletności, inne operatory podobne do równości można spotkać w skryptach powłoki:

  • [ "$a" -eq "$b" ]: standardowy [operator do porównywania liczb całkowitych dziesiętnych. Niektóre [implementacje dopuszczają spacje wokół liczb, niektóre pozwalają na dowolne wyrażenia arytmetyczne, ale to nie jest przenośne. Przenośnie można [ "$((a))" -eq "$((b))" ]do tego użyć . Patrz również [ "$((a == b))" -ne 0 ], co byłoby równoważne średnia (z wyjątkiem POSIXly zachowanie jest określony tylko wtedy $ai $bzawierają całkowitą stałych) z:
  • ((a == b)), z ksh, a także znalezione w zshi bash, zwraca true, jeśli ocena wyrażenia arytmetycznego przechowywanego w $adaje taką samą liczbę jak dla $b. Zwykle służy do porównywania liczb. Zauważ, że istnieją różnice między powłokami dotyczące sposobu obliczania wyrażeń arytmetycznych i obsługiwanych liczb (na przykład bash i niektóre implementacje / wersje ksh nie obsługują liczb zmiennoprzecinkowych lub traktują liczby z wiodącymi zerami jako liczby ósemkowe).

  • expr "$a" = "$b"dokonuje porównania liczb, jeśli oba operandy są rozpoznawane jako dziesiętne liczby całkowite (niektóre pozwalają na spacje wokół liczby), a w przeciwnym razie sprawdza, czy dwa operatory łańcuchowe mają tę samą kolejność sortowania. Byłoby to również nie dla wartości $alub $bktóre są exproperatorzy podoba (, substr...

  • awk 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": jeśli $ai $bsą rozpoznawane jako liczby (przynajmniej dziesiętne liczby całkowite i zmiennoprzecinkowe, takie jak 1,2, -1,5e-4, wiodące spacje końcowe są ignorowane, niektóre rozpoznają również wartości szesnastkowe, ósemkowe lub cokolwiek rozpoznawanego przez strtod()), wówczas wykonywane jest porównanie numeryczne. Inaczej, w zależności od implementacji, to albo porównanie ciąg bajt do bajta, lub jak za exprpomocą strcoll()porównania, że to, czy $ai $bporządek to samo.

Zobacz też:

Stéphane Chazelas
źródło
13

Są one równoważne w bash:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]

Pierwsze dwie zmienne $ x nie muszą być cytowane. Bash wykonuje dzielenie słów i rozwijanie nazw ścieżek wewnątrz [ale nie wewnątrz [[:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 

[[ $x = "$y" ]]to porównanie ciągów, ale [[ $x = $y ]]wyrażenie pasujące do wzorca:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0

-eq jest przeznaczony do użycia tylko z liczbami całkowitymi:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0

Zobacz także BashFAQ / 031: Jaka jest różnica między testem, [i [[? .

Lri
źródło