W Bash można porównać dwie liczby całkowite za pomocą wyrażenia warunkowego
arg1 OP arg2
OP jest jednym z
-eq
,-ne
,-lt
,-le
,-gt
lub-ge
. Te arytmetyczne operatory binarne zwracają prawdę, jeśli arg1 jest równe, nie równe, mniejsze niż, mniejsze lub równe, większe niż, większe lub równe arg2 , odpowiednio. Arg1 i arg2 mogą być dodatnimi lub ujemnymi liczbami całkowitymi.
lub wyrażenie arytmetyczne:
<= >= < >
porównanie
== !=
równość i nierówność
Dlaczego mamy dwa różne sposoby porównywania dwóch liczb całkowitych? Kiedy używać którego?
Na przykład [[ 3 -lt 2 ]]
używa wyrażenia warunkowego, a (( 3 < 2 ))
używa wyrażenia arytmetycznego. Obie zwracają 0, gdy porównanie jest prawdziwe.
Czy porównując dwie liczby całkowite, te dwie metody mogą być zawsze używane zamiennie? Jeśli tak, dlaczego Bash ma dwie metody zamiast jednej?
Komentarze
Odpowiedź
Tak, mamy dwa różne sposoby porównywania dwóch liczb całkowitych.
Wygląda na to, że te fakty nie są szeroko akceptowane na tym forum:
-
W idiomie
[ ]
operatory porównania arytmetycznego to-eq
,-ne
,-lt
,-le
,-gt
i-ge
.Ponieważ znajdują się one również w poleceniu testowym i w
[[ ]]
.Tak, w tych idiomach,
=
,<
itd. Są operatory ciągów. -
W idiomie
(( ))
operatory porównania arytmetycznego to==
,!=
,<
,<=
,>
i>=
.Nie, to nie jest „arytm rozwinięcie etyczne ”(zaczynające się od
$
) jako$(( ))
. W man bash jest zdefiniowane jako „Polecenie złożone”.Tak, działa zgodnie z tymi samymi regułami (wewnętrznie) co „Rozwinięcie arytmetyczne”, ale nie ma wyjścia, a jedynie wartość wyjścia. Można go użyć w ten sposób:
if (( 2 > 1 )); then ...
Dlaczego mamy dwa różne sposoby porównywania dwóch liczb całkowitych?
Wydaje mi się, że ten ostatni (( ))
został opracowany jako prostszy sposób wykonywania testów arytmetycznych. Jest prawie taki sam jak $(( ))
, ale po prostu nie ma wyjścia.
Dlaczego dwa? Cóż, to samo, dlaczego mamy dwa printf
(zewnętrzne i wbudowane) lub cztery testy (zewnętrzne test
, wbudowane test
, [
i [[
). To jest sposób, w jaki muszle rosną, poprawiając jeden obszar w ciągu jednego roku, ulepszając inny w następnym.
Kiedy użyć którego?
To bardzo trudne pytanie, ponieważ nie powinno być żadnej skutecznej różnicy. Oczywiście istnieją pewne różnice w sposobie działania [ ]
i (( ))
w działaniu wewnętrznym, ale: co lepiej porównać dwie liczby całkowite? Dowolny !.
Czy podczas porównywania dwóch liczb całkowitych te dwie metody mogą być zawsze używane zamiennie?
W przypadku dwóch liczb muszę powiedzieć, że tak.
Ale w przypadku zmiennych, rozszerzenia , operacje matematyczne mogą istnieć kluczowe różnice, które powinny faworyzować jedną lub drugą. Nie mogę powiedzieć, że absolutnie oba są równe. Po pierwsze, (( ))
może wykonać kilka operacji matematycznych po kolei:
if (( a=1, b=2, c=a+b*b )); then echo "$c"; fi
Jeśli tak, dlaczego Bash ma dwie metody zamiast jednej?
Jeśli obie są pomocne, dlaczego nie ?.
Komentarze
-
=
to przypisanie, a==
to porównanie w rozwinięciach arytmetycznych. Pytanie cytuje to poprawnie. Ale odpowiedź jest błędna. - Ponadto
(
nie jest słowem zastrzeżonym w bashu, więc nie ma potrzeby umieszczania spacji wokół((
, ponieważ w przeciwieństwie do[
lub[[
Answer
Historycznie rzecz biorąc, polecenie test
istniało jako pierwsze (przynajmniej od Siódma edycja Unixa w 1979). Użył operatorów =
i !=
do porównania ciągów oraz -eq
, -ne
, -lt
itd., Aby porównać liczby. Na przykład test 0 = 00
to fałsz, ale test 0 -eq 00
to prawda. Nie wiem, dlaczego wybrano tę składnię, ale być może chodziło o uniknięcie używania <
i >
, które powłoka miałaby przeanalizowane jako operatory przekierowania. Polecenie test
kilka lat później otrzymało inną składnię: [ … ]
jest równoważne z test …
.
[[ … ]]
składnia warunkowa, wewnątrz której <
i >
może być używany jako operatory bez cytowania, został dodany później, w ksh. Zachował wsteczną kompatybilność z [ … ]
, więc używał tych samych operatorów, ale dodał <
i >
, aby porównać ciągi (na przykład [[ 9 > 10 ]]
ale [[ 9 -lt 10 ]]
). Aby uzyskać więcej informacji, zobacz używając pojedynczego lub podwójnego nawiasu – bash
Wyrażenia arytmetyczne również pojawiły się później niż test
polecenie,
w powłoce Korna , w pewnym momencie w latach 80. Podążali za składnią języka C, który był bardzo popularny w kręgach uniksowych. Dlatego użyli operatorów C „s:==
dla równości,<=
dla mniejszego lub równego itd.
Siódma edycja systemu Unix nie zawierała wyrażeń arytmetycznych, ale zawierała polecenie expr
, które również implementowało Składnia podobna do C dla operacji na liczbach całkowitych, w tym operatory porównania. W skrypcie powłoki znaki <
i >
musiały być cytowane, aby chronić je przed powłoką, np. if expr 1 \< 2; …
jest odpowiednikiem if test 1 -lt 2; …
. Dodanie wyrażeń arytmetycznych do powłoki sprawiło, że większość zastosowań expr
stała się przestarzała, więc nie jest dziś dobrze znana.
W skrypcie sh, ty d generalnie używaj wyrażeń arytmetycznych do obliczania wartości całkowitych i [ … ]
do porównywania liczb całkowitych.
if [ "$((x + y))" -lt "$z" ]; then …
W ksh , bash lub zsh, możesz użyć ((…))
dla obu.
if ((x + y < z)); then …
jest przydatny, jeśli chcesz używać warunków warunkowych obejmujących elementy inne niż liczby całkowite.
Odpowiedź
Zgodnie z testowa strona podręcznika man, = i! = są używane do porównywania ciągów, podczas gdy wyrażenia -eq, -gt, -lt, -ge, -le i -ne są porównaniami całkowitymi. Zawsze postępowałem zgodnie z tą konwencją podczas pisania skryptów powłoki i zawsze działa. Pamiętaj, że jeśli masz zmienne w wyrażeniu, może być konieczne zacytowanie zmiennych w jakiś sposób, aby uniknąć porównania zerowego.
Na papierze porównujemy ciąg / liczbę bez większego zastanowienia.Z drugiej strony komputer nie wie, czy 987 to liczba, czy ciąg znaków. Potrzebujesz różnych operatorów, aby powiedzieli komputerowi, co ma zrobić, aby uzyskać właściwy wynik. tutaj zawiera dodatkowe informacje wyjaśniające część historii. Zasadniczo zmienne nie mają typu i pozostały takie ze względu na zgodność historyczną.
Komentarze
- W moim poście
=
i!=
to operatory arytmetyczne, podczas gdy strona podręcznikatest
zawiera tylko operatory wyrażeń warunkowych.
= != < <= > >=
porównaj ciągi znaków .1 -eq 01
ale1 != 01
i8 -lt 42
ale8 > 42