Porównywanie liczb całkowitych: wyrażenie arytmetyczne lub wyrażenie warunkowe


20

W Bash dwie liczby całkowite można porównać za pomocą wyrażenia warunkowego

arg1 OP arg2

PO jest jednym -eq, -ne, -lt, -le, -gt, i -ge. Te arytmetyczne operatory binarne zwracają wartość true, jeśli arg1 jest odpowiednio równy, nie równy, mniejszy, mniejszy lub równy, większy niż lub większy niż lub równy arg2 . 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 stosować który?

Na przykład [[ 3 -lt 2 ]]używa wyrażenia warunkowego i (( 3 < 2 ))używa wyrażenia arytmetycznego. Oba zwracają 0, gdy porównanie jest prawdziwe

Czy porównując dwie liczby całkowite, zawsze można stosować te dwie metody zamiennie? Jeśli tak, to dlaczego Bash ma dwie metody zamiast jednej?


1
= != < <= > >=porównaj ciągi . 1 -eq 01ale 1 != 01i 8 -lt 42ale8 > 42
dave_thompson_085 24.04.16

Są przeciążone wyrażeniami arytmetycznymi.
Tim

1
będziesz musiał przeszukać dzienniki zmian bash, aby dowiedzieć się, kiedy każda funkcja została dodana. Podejrzewam, że wyrażenia arytmetyczne zostały dodane znacznie później niż polecenie testowe.
glenn jackman

Nie pytam o porównywanie ciągów. @muru.
Tim

Odpowiedzi:


28

Tak, mamy dwa różne sposoby porównywania dwóch liczb całkowitych.

Wygląda na to, że te fakty nie są powszechnie akceptowane na tym forum:

  1. Wewnątrz idiomu [ ]operatory dla arytmetyki porównań -eq, -ne, -lt, -le, -gti -ge.

    Ponieważ są one również wewnątrz polecenia testowego i wewnątrz [[ ]].

    Tak Wewnątrz idiomów, =, <, itd. Są operatory łańcuchowe.

  2. Wewnątrz idiomu (( ))operatory dla arytmetyki porównań ==, !=, <, <=, >, i >=.

    Nie, nie jest to „rozszerzenie arytmetyczne” (zaczynające się od a $) as $(( )). Jest zdefiniowany jako „Polecenie złożone” w man bash.

    Tak, zgodnie z tymi samymi zasadami (wewnętrznie), co „rozszerzenie arytmetyczne”, nie ma danych wyjściowych, a jedynie wartość wyjściową. Można go użyć w następujący sposób:

if (( 2 > 1 )); then ...

Dlaczego mamy dwa różne sposoby porównywania dwóch liczb całkowitych?

Myślę, że ten ostatni (( ))został opracowany jako prostszy sposób wykonywania testów arytmetycznych. Jest prawie taki sam jak ten, $(( ))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 [[). W ten sposób rosną muszle, poprawiając niektóre obszary w ciągu jednego roku, poprawiając inne w następnym roku.

Kiedy stosować który?

To bardzo trudne pytanie, ponieważ nie powinno być skutecznej różnicy. Oczywiście istnieją pewne różnice w sposobie [ ]pracy i(( )) pracy wewnętrznej, ale: co lepiej porównać dwie liczby całkowite? Każdy!

Czy porównując dwie liczby całkowite, zawsze można stosować te dwie metody zamiennie?

W przypadku dwóch liczb jestem zmuszony powiedzieć tak.
Ale w przypadku zmiennych, rozszerzeń, operacji matematycznych mogą występować kluczowe różnice, które powinny sprzyjać jednemu lub drugiemu. Nie mogę powiedzieć, że absolutnie oba są równe. Po pierwsze, (( ))mogą wykonywać kolejno kilka operacji matematycznych:

if (( a=1, b=2, c=a+b*b )); then echo "$c"; fi

Jeśli tak, to dlaczego Bash ma dwie metody zamiast jednej?

Jeśli oba są pomocne, dlaczego nie?


1
=jest zadaniem i ==stanowi porównanie rozszerzeń arytmetycznych. Pytanie cytuje to poprawnie. Ale odpowiedź jest zła.
ceving

12

Historycznie testkomenda istniała jako pierwsza (przynajmniej jeszcze w 7. edycji Unix w siódmej edycji ). Stosowany operatorów =i !=porównać strun, i -eq, -ne, -lt, itd., Aby porównać numery. Na przykład test 0 = 00jest fałszywy, ale test 0 -eq 00jest prawdziwy. Nie wiem, dlaczego wybrano tę składnię, ale być może trzeba było unikać używania <i >, które powłoka analizowałaby jako operatory przekierowania. testPolecenie dostał inną składnię kilka lat później: [ … ]jest równoważna test ….

[[ … ]]Składni warunkowe, wewnątrz której <i >może być stosowany jako podmiotów bez podania dodano później, w KSH. Zachował kompatybilność wsteczną [ … ], więc używał tych samych operatorów, ale dodawał <i >porównywał ciągi znaków (na przykład, [[ 9 > 10 ]]ale [[ 9 -lt 10 ]]). Aby uzyskać więcej informacji, zobacz używanie pojedynczego lub podwójnego nawiasu klamrowego

Wyrażenia arytmetyczne pojawiły się później niż testpolecenie, w powłoce Korna , w pewnym momencie w latach 80. Postępowali zgodnie ze składnią języka C, który był bardzo popularny w kręgach uniksowych. Dlatego używali operatorów C: ==dla równości, <=dla mniejszej lub równej itp.

Unix Siódma Edycja nie miała wyrażeń arytmetycznych, ale miała exprkomendę , która również implementowała składnię podobną do C dla operacji na liczbach całkowitych, w tym operatorów porównania. W skrypcie powłoki znaki <i znaki >muszą być cytowane, aby chronić je przed powłoką, np. if expr 1 \< 2; …Jest równoważne if test 1 -lt 2; …. Dodanie wyrażeń arytmetycznych do powłoki spowodowało, że większość zastosowań była exprprzestarzała, więc nie jest ona dziś dobrze znana.

W skrypcie sh zwykle używasz wyrażeń arytmetycznych do obliczania wartości liczb całkowitych i [ … ]do porównywania liczb całkowitych.

if [ "$((x + y))" -lt "$z" ]; then 

W skrypcie ksh, bash lub zsh możesz używać ((…))obu.

if ((x + y < z)); then 

[[ … ]]Forma jest przydatna, jeśli chcesz skorzystać z udziałem warunkowe rzeczy inne niż liczb całkowitych.


1

Według strony podręcznika testowego do porównań łańcuchów używane są = i! =, Natomiast wyrażenia -eq, -gt, -lt, -ge, -le i -ne są porównaniami liczb całkowitych. Zawsze przestrzegałem tej konwencji podczas pisania skryptów powłoki i zawsze działa. Należy pamiętać, ż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 dokonujemy porównań ciągów / liczb bez namysłu. Z drugiej strony komputer nie wie, czy 987 jest liczbą, czy ciągiem znaków. Potrzebujesz różnych operatorów, którzy powiedzą komputerowi, co zrobić, aby uzyskać właściwy wynik. Jest tu kilka dodatkowych informacji , które wyjaśniają część historii. Zasadniczo zmienne są nietypowe i pozostały w ten sposób dla historycznej zgodności.


W moim poście, = i !=są operatory arytmetyczne, natomiast podręcznika z testtylko pokazuje warunkowe operatory wyrażeń.
Tim
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.