Порівняння цілих чисел: арифметичний вираз або умовний вираз


20

У Bash два цілих числа можна порівняти, використовуючи умовне вираження

arg1 OP arg2

OP є одним з -eq, -ne, -lt, -le, -gt, або -ge. Ці арифметичні двійкові оператори повертають істину, якщо arg1 дорівнює, не дорівнює, менше, менше або дорівнює, більше або більше, або дорівнює arg2 відповідно. Arg1 і arg2 можуть бути натуральними чи від’ємними цілими числами.

або арифметичний вираз:

<= >= < > порівняння

== != рівність і нерівність

Чому у нас є два різні способи порівняння двох цілих чисел? Коли використовувати який?

Наприклад, [[ 3 -lt 2 ]]використовує умовне вираження та (( 3 < 2 ))використовує арифметичне вираження. Обидва повертають 0, коли порівняння вірно

Чи можна порівнювати два цілих числа, якщо ці два методи завжди взаємозамінні? Якщо так, то чому Bash має два методи, а не один?


1
= != < <= > >=порівняйте рядки . 1 -eq 01але 1 != 01і 8 -lt 42але8 > 42
dave_thompson_085

Вони перевантажені арифметичними виразами.
Тім

1
Вам доведеться шукати в журналах змін bash, щоб дізнатися, коли кожна функція була додана. Я підозрюю, що арифметичні вирази були додані набагато пізніше, ніж команда тесту.
glenn jackman

Я не запитую про порівняння рядків. @muru.
Тім

Відповіді:


28

Так, у нас є два різних способи порівняння двох цілих чисел.

Схоже, ці факти не широко прийняті на цьому форумі:

  1. Усередині ідіоми [ ]оператори для арифметичного порівняння -eq, -ne, -lt, -le, -gtі -ge.

    Оскільки вони також знаходяться всередині тестової команди та всередині [[ ]].

    Так в цій ідіоми, =, <і т.д. рядкові оператори.

  2. Усередині ідіоми (( ))оператори для арифметичного порівняння ==, !=, <, <=, >, і >=.

    Ні, це не "Арифметичне розширення" (яке починається з а $) як $(( )). Він визначається як "З'єднана команда" в man bash.

    Так, воно дотримується тих же правил (внутрішньо) "Арифметичне розширення", але не має виводу, лише значення виходу. Це можна використовувати так:

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

Чому у нас є два різні способи порівняння двох цілих чисел?

Я здогадуюсь, що останній (( ))був розроблений як більш простий спосіб виконання арифметичних тестів. Він майже такий же, як і, $(( ))але просто не має виходу.

Чому два? Ну так же , як , чому у нас є два printf(зовнішня і вбудована) або чотири випробування (зовнішня test, вбудована команда test, [і [[). Ось так виростають раковини, покращуючи деяку площу за один рік, покращуючи деякі інші в наступному році.

Коли використовувати який?

Це дуже складне питання, оскільки не повинно бути ефективних різниць. Звичайно, існують певні відмінності у способі [ ]роботи та (( ))твору всередині, але: що краще порівняти два цілих числа? Будь-яка!

Чи можна порівнювати два цілих числа, якщо ці два методи завжди взаємозамінні?

На два числа я змушений сказати "так".
Але для змінних, розширень, математичних операцій можуть бути ключові відмінності, які мають сприяти тому чи іншому. Не можу сказати, що абсолютно обидва рівні. Для одного, команда (( ))може виконувати кілька математичних операцій послідовно:

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

Якщо так, то чому Bash має два методи, а не один?

Якщо обидва корисні, чому б і ні?


1
=є завданням і ==є порівнянням в арифметичних розширеннях. Питання цитує це правильно. Але відповідь неправильна.
закінчення

12

Історично testкоманда існувала спочатку (принаймні, ще до сьомої редакції Unix у 1979 році). Раніше оператори =і !=порівняння рядків, і -eq, -ne, -ltі т.д. для порівняння чисел. Наприклад, test 0 = 00помилково, але test 0 -eq 00правда. Я не знаю, чому був вибраний цей синтаксис, але можливо, це було уникнути використання <та >, який оболонку розібрав би як операторів перенаправлення. Через testкілька років команда отримала ще один синтаксис: [ … ]еквівалентна test ….

[[ … ]]Умовний синтаксис, всередині якого <і >може бути використаний в якості операторів , не цитуючи, був доданий пізніше, в KSH. Він зберігав зворотну сумісність із [ … ], тому використовував ті самі оператори, але додав <і >для порівняння рядків (наприклад, [[ 9 > 10 ]]але [[ 9 -lt 10 ]]). Для отримання додаткової інформації див. Використання однієї або подвійної дужки - bash

Арифметичні вирази також з'явилися пізніше, ніж testкоманда, в оболонці Корна , якийсь час у 1980-х. Вони дотримувалися синтаксису мови С, який був дуже популярний у колах Unix. Таким чином, вони використовували оператори C: ==для рівності, <=для менших або рівних тощо.

У Unix сьомої редакції не було арифметичних виразів, але вона мала exprкоманду , яка також реалізувала C-подібний синтаксис для цілих операцій, включаючи оператори порівняння. У сценарії оболонки символи <та >їх потрібно було цитувати, щоб захистити їх від оболонки, наприклад if expr 1 \< 2; …, еквівалентно if test 1 -lt 2; …. Додавання арифметичних виразів до оболонки зробило більшість застосувань exprзастарілими, тому це невідомо сьогодні.

У скрипті sh ви зазвичай використовуєте арифметичні вирази для обчислення цілого значення та [ … ]для порівняння цілих чисел.

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

У сценарії ksh, bash або zsh ви можете використовувати ((…))і те, і інше.

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

[[ … ]]Форма корисна , якщо ви хочете використовувати умовні з участю інших , ніж цілі речей.


1

Відповідно до сторінки man test, = і! = Використовуються для порівняння рядків, тоді як вирази -eq, -gt, -lt, -ge, -le та -ne є цілими порівняннями. Я завжди дотримувався цієї конвенції, коли писав сценарії оболонок, і це завжди працює. Майте на увазі, що якщо у вас є змінні в виразі, вам може знадобитися цитувати змінні певним чином, щоб уникнути нульового порівняння.

На папері ми робимо порівняння рядків і чисел без особливої ​​думки. Комп'ютер з іншого боку не знає, чи є 987 числом або рядком символів. Вам потрібні різні оператори, щоб сказати комп’ютеру, що робити, щоб отримати правильний результат. Існує деяка додаткова інформація тут , що пояснює деякі з історії. По суті, змінні нетипізовані і таким чином залишилися для історичної сумісності.


У моєму дописі є = і !=арифметичні оператори, в той час як на сторінці відображаються testлише оператори умовного вираження.
Тім
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.