Bash if порівняння чисел. Умова if-else BASH

Bash if порівняння чисел. Умова if-else BASH

Умова if-else застосовується у скриптах BASHдуже часто. Сама умова має дещо дивний вид [[ умова ]]. Зверніть увагу на відступи. Без них умова не працюватиме. Наводжу список логічних операторів для умови [[? ]]:

Список логічних операторів, які
використовуються для конструкції if-then-else-fi

#!/bin/bash if [[ $1 > 2 ]] then # якщо відповідає умові [[ ? ]] echo $1" більше 2" else # якщо не відповідає умові echo $1" менше 2 або 2" fi

Комусь із вас здасться дивним оператор рівності -eq. Спробуйте використати звичні оператори >

Допустимо у вас є скрипт і потрібна перевірка користувача. Якщо користувач не root, зупинка скрипта відбудеться.

#!/bin/bash if [ "$(whoami)" != "root" ]; then echo "У вас немає прав для запуску $0." exit 1; fi

Часто потрібно перевіряти змінну наявність значення. Якщо нічого в змінній немає, можна зупинити скрипт.

#!/bin/bash if [-n "$num"]; then "змінна щось має і можна запустити інший процес" else echo "порожня змінна, зупиняємо скрипт" exit 0; fi

Якщо змінна порожня, її можна наповнити.

#!/bin/bash if [-z "$num"]; then echo "змінна порожня" num=1 else echo "num="$num fi

Порожній змінній можна встановити значення за замовчуванням. Такий запис коротший, ніж у попередньому прикладі.

#!/bin/bash # Записати DEFAULT, якщо аргументи командного рядка відсутні [ -z "$arg1" ] && arg1=DEFAULT echo $arg1

Порівняння рядків у Bash не викликає жодних проблем до тих пір, доки не виникає завдання порівняти два рядки, не враховуючи регістр символів. Я наведу кілька варіантів розв'язання задач, які використовую сам. Особливістю цих рішень є використання лише вбудованих можливостей оболонки Bash.

Для початку я створю дві змінні str1 і str2 , що містять рядки, що підлягають порівнянню. Саме вони будуть використовуватись у таких прикладах коду.

#!/bin/bash str1 = "String To Compare" str2 = "string to compare"

У першому варіанті реєстронезалежного порівняння рядків, який я хочу запропонувати, використовується управління опціями оболонки за допомогою вбудованої команди shopt.

shopt -s nocasematch [[ $str1 == $str2 ]] && echo "match" || echo "not match" shopt -u nocasematch

Наступний варіант реєстронезалежного порівняння рядків ґрунтується на принципі самостійного приведення рядків до загального регістру. Цей варіант коду працює на версії Bash 4 та новішої. Використання його на більш ранній версії Bash призведе до помилки.

Так, для порівняння рядків, що приведені до нижнього регістру, можна використовувати наступний варіант коду.

[[ " $( str1 , ) " == " $( str2 , ) " ]] && echo "match" || echo "not match"

Якщо ви хочете привести порівнювані рядки до верхнього регістру, можна використовувати наступний код.

[[ " $( str1 ^^ ) " == " $( str2 ^^ ) " ]] && echo "match" || echo "not match"

Як альтернативний варіант, приведення рядків до єдиного регістру може бути виконано в момент декларування змінних. Для цього використовується вбудована команда оболонки declare.

Щоб декларувати змінну, що містить текст у нижньому регістрі, використовується наступний код.

#!/bin/bash declare -l str = "Camel Case String"

В результаті виконання цього коду, в змінній str буде міститися рядок в нижньому регістрі, незважаючи на те, що рядок, що присвоюється, була записана в camel case. Змінити регістр вже заданого змінного рядка можна наступним чином.

#!/bin/bash str = "Camel Case String" declare -l str str = $str echo $str

Щоб привести рядок до верхнього регістру, у наведеному прикладі коду слід змінити виклик команди declare , використовуючи замість ключа -l ключ -u .

Тепер реєстронезалежне порівняння рядків з використанням команди declare може бути виконано наступним чином.

declare -l str1_l = $str1 declare -l str2_l = $str2 [[ $str1_l == $str2_l ]] && echo "match" || echo "not match"

Будь-який із розглянутих варіантів реєстронезалежного порівняння рядків може бути використаний при написанні сценаріїв Bash. Тому, якщо ви використовуєте версію Bash 4 і вище, можете вибирати той, який сподобався вам більше. Якщо ж версія Bash нижче 4, то слід використовувати перший варіант із завданням опції nocasematch за допомогою вбудованої команди оболонки shopt.

У сценаріях оболонки Bash ми можемо здійснити порівняння чисел. Для виконання операції порівняння чисел Bash необхідно використовувати стан “test” в межах if або loop. У цьому пості ми розповімо вам, як порівняти числа в bash.

Оператори для Баш порівняння чисел

операторщо робитьприклад
-eqпорівняти цифри в bash для рівності, повертає 0, якщо рівноif [ $a -eq $b ] then
-geпорівняння чисел у bash, якщо більше чи одно. Результат повертає 0, якщо більше чи одноif [ $a -ge $b ] then
-gtпорівнює числа bash, якщо більше.if [ $a -gt $b ] then
-leпорівнює числа bash, якщо менше або дорівнює.if [ $a -le $b ] then
-ltпорівнює числа bash, якщо менше.if [ $a -lt $b ] then
-neпорівнює числа в bash, якщо не одно чи ні.if [ $a -ne $b ] then

Приклади в деталях операторів порівняння числа Bash:

1. оператор-eq

Цей оператор порівнює числа, перевірятиме значення одно чи ні. Якщо воно рівне, то повертається 0.

# cat test.sh #!/bin/bash echo "введіть значення змінної" read a echo "введіть значення змінної" read b if [ $a -eq $b ] then echo "Повертане значення: $?" echo "a і b рівні" else echo "Повертане значення: $?" echo "a і b не рівні" fi #

Виконання:

# sh test.sh введіть значення змінної 2 введіть значення змінної 3 значення, що повертається:: 1 a і b не рівні # sh test.sh введіть значення змінної 2 введіть значення змінної 2 Повертається значення:: 0 a і b рівні #

У наведеному вище прикладі ми взяли числа 2 і 3 вперше і система повернула значення 1, проте, коли ми прийняли однакові значення а і б, змінна повертає нульове значення.

2. оператор-ge

Цей оператор порівнює числа та перевіряє значення на більше чи одно. Якщо значення більше або рівне, то він повертається значення 0.

# cat test1.sh #!/bin/bash #програма порівняння для -ge echo "введіть значення змінної" read a echo "введіть значення для змінної b" read b if [ $a -ge $b ] then echo "повертане значення: : $?" echo "a більше або одно b" else echo "значення, що повертається:: $?" echo "a не більше або одно b" fi #

3. оператор -gt

Цей оператор порівняння чисел перевірятиме число на більше. Якщо значення більше, повертає 0.

# cat test2.sh #!/bin/bash #програма порівняння для -gt b=100 echo "введіть значення більше 100" read a if [ $a -gt $b ] then echo "Дуже добре" else echo "Не дуже добре "fi

4. оператор-le

Цей оператор порівняння числа перевірятиме значення на менше або одно. Якщо воно менше або дорівнює, то значення 0, що повертається.

#програма порівняння для -le b=5 echo "введіть значення менше або дорівнює 5" read a if [ $a -le $b ] then echo "все вірно" else echo "не вірно" fi #

5. оператор-lt

Цей оператор порівняння числа перевірятиме значення на менше. Якщо число менше, то значення 0, що повертається.

Цей топік є четвертим топіком циклу «Мова командного інтерпретатора bash». Він розповідатиме про такі керуючі структури мови, як умовні оператори. Але перед тим, як перейти до їх опису, необхідно зупинитися на деяких нюансах, які зроблять розгляд нижчевикладеного матеріалу зрозумілішим.
По-перше, розберемо, що таке перелік команд. Список команд – це одиночна команда, конвеєр або послідовність команд/конвеєрів, розділених одним із наступних операторів: ";", "&&", "||", завершена крапкою з комою.
; - Оператор послідовного виконання кількох команд. Кожна наступна команда починає виконуватися лише після завершення попередньої (не важливо, успішного чи ні);
&& - оператор виконання команди лише після успішного виконання попередньої;
|| - оператор виконання команди лише після помилкового виконання попередньої.
Кодом успішного завершення є 0, а помилкового – не нуль (залежить від типу помилки). Не слід плутати зі звичайними мовами програмування, коли 1 є аналогом true, а 0 – false.
Тепер можна розпочати безпосередній розгляд умовних операторів.

Оператор варіантів case

Загальний синтаксис оператора case:

case значення in
шаблон1) список1;;
шаблон2 | шаблон3) список2;;
esac

Логічна послідовність виконання оператора case:
а) шукається перший шаблон, що збігається зі значенням;
б) якщо його знайдено, виконується відповідний йому список команд, завершений ";;";
в) керування передається операторам, наступним за конструкцією case.
Шаблон та список поділяються символом ")". Одному списку команд може відповідати декілька умов, тоді їх потрібно розділяти символом "|".
У шаблонах можна використовувати символи "*", "?", "", про які було розказано у другому топіці циклу. З їхньою допомогою можна реалізувати інструкцію, що діє як default в операторі switch таких мов, як C, PHP.
Наведу приклад використання case:
echo -n "[Універсальний просмоторник] Вкажіть ім'я файлу: "; read File case "$File" in *.jpg|*.gif|*.png) eog $File;; *.pdf) evince $File;; *.txt) less $File;; *.html) firefox $File;; /dev/*) echo "Ну це страшні файли." ;;; *) echo "Ну гаразд, гаразд - не такий вже й універсальний." echo "Цей тип файлів мені не знайомий. Не знаю, чим його переглянути." ;;; esac
Ще один приклад використання конструкції case:
echo "Помилка. Кому надіслати повідомлення?" echo "Начальнику: b" echo "Колегам: c" echo "Нікому: any key"< error.log;; c|C) mail –s "Help! error log" –c denis nick < error.log;; *) echo "error"; exit;; esac

Умовний оператор if

Загальний синтаксис оператора if:

if список1 then
список2

fi

Квадратні дужки тут вказують на необов'язкові конструкції. Логічна послідовність виконання оператора case:
а) виконується список1;
б) якщо його виконано без помилок, виконується список2. В іншому випадку виконується список3, і якщо він завершується без помилок – список4. Якщо ж список3 повертає код помилки, виконується список5;
в) управління передається операторам, що йдуть за конструкцією if.
Наведу приклад використання if:
if grep -q Bash file then echo "Файл містить щонайменше одне слово Bash." fi
Коли if та then розташовуються в одному рядку, то конструкції if і then повинні завершуватися точкою з комою. Наприклад:
$ if [$? -ne 0]; then echo “Error”; fi
Тепер, знаючи про можливість розташовувати if і then в одному рядку, перепишемо вищезгаданий приклад:
if grep -q Bash file; then echo "Файл містить слово Bash." fi

Оператор test та умовні вирази

У наведеному вище прикладі замість аналізу коду завершення використана перевірка умови. Дві форми такої перевірки є еквівалентними: вбудована команда test і [умова]. Наприклад, для перевірки існування файлу потрібно написати:
test –e<файл>
або
[-e<файл> ]
Якщо використовуються квадратні дужки, вони обов'язково повинні бути відокремлені один від одного пробілом, тому що "[" - це назва команди, а "]" - обов'язковий останній аргумент її завершення.
У разі успішної перевірки умови повертається 0, а у разі помилковості – код помилки 1.
Команда test може перевіряти рядок на порожнечу. Непорожній рядок призводить до коду завершення 0. Порожньо, відповідно – 1. Наприклад:
$test $USER; echo $? 0
Конструкція "" більш універсальна, ніж "". Цей розширений варіант команди test. Усередині цієї конструкції не виконується жодної додаткової інтерпретації імен файлів і не проводиться розбиття аргументів на окремі слова, але допускається підстановка параметрів та команд. Наприклад:
file=/etc/passwd if [[ -e $file ]] then echo “Файл паролів знайдено.” fi
Конструкція "" краща, ніж "", оскільки допоможе уникнути деяких логічних помилок. Наприклад, оператори "&&", "||", "<" и ">" всередині " " цілком допустимі, тоді як усередині " " породжують повідомлення помилках.
Конструкція "(())" дозволяє проводити обчислення арифметичних виразів усередині неї. Якщо результатом обчислень є нуль, повертається код помилки. Ненульовий результат обчислень дає код повернення 0. Тобто повна протилежність інструкціям test та "", що обговорювалися вище.
Оператор if дозволяє допускати наявність вкладених перевірок:
if echo "Наступний *if* знаходиться всередині першого *if*." if [[$comparison = "integer"]] then ((a< b)) else [[ $a < $b ]] fi then echo "$a меньше $b" fi

Умовні вирази можна комбінувати за допомогою звичайних логічних операцій:
! <выражение>- Заперечення;
<выражение1>-a<выражение2>- Логічне І;
<выражение1>-o<выражение2>- Логічне АБО.

Елементарні умовні вирази для файлів:
-e – файл існує;
-f - звичайний файл (не каталог і файл пристрою);
-s – ненульовий розмір файлу;
-d – файл є каталогом;
-b - файл є блоковим пристроєм (floppy, cdrom тощо);
-c – файл є символьним пристроєм (клавіатура, модем, звукова карта тощо);
-p – файл є каналом;
-h - файл є символічним посиланням;
-L - файл є символічним посиланням;
-S – файл є сокетом;
-t - Файл пов'язаний з термінальним пристроєм;
-r - файл доступний для читання (користувачу, який запустив сценарій);
-w - файл доступний для запису (користувачу, який запустив сценарій);
-x - файл доступний для виконання (користувачу, який запустив сценарій);
-g - (sgid) прапор для файлу чи каталогу встановлено;
-u - (suid) прапорець для файлу встановлений;
-k – прапор sticky bit встановлений;
-O – ви є власником файлу;
-G - ви належите до тієї ж групи, як і файл;
-N – файл був модифікований з моменту останнього читання;
файл1 -nt файл2 - файл1 новіший, ніж файл2;
файл1 -ot файл2 - файл1 старіший, ніж файл2;
файл1 -ef файл2 – файл1 і файл2 є «жорсткими» посиланнями на той самий файл.

Елементарні умовні вирази для порівняння рядків:
-z рядок – довжина рядка дорівнює 0;
-n рядок – довжина рядка не дорівнює 0;
рядок1 == рядок2 – рядки збігаються (аналог “=”);
рядок1 !== рядок2 – рядки не збігаються (аналог “!=”);
рядок1< строка2 – строка1 предшествует строке2 в лексикографическом порядке;
рядок1 > рядок2 – рядок1 слідує за рядком2 в лексикографічному порядку.
Арифметичний умовний вираз має формат:
аргумент1 операція аргумент2, де аргументами є цілі числа, і допустимі такі операції:
-eq - одно;
-ne - не дорівнює;
-lt – менше;
-le – менше чи одно;
-gt - Більше;
-ge – більше чи одно;
< - меньше (внутри двойных круглых скобок);
<= - меньше или равно (внутри двойных круглых скобок);
> - більше (всередині подвійних круглих дужок);
>= - більше чи одно (всередині подвійних круглих дужок).

Перепишемо попередній приклад із використанням оператора if:
echo "Помилка. Кому надіслати повідомлення?" echo "Начальнику: b" echo "Колегам: c" echo "Нікому: any key" read answer if [ "$answer" == "b" –o "$answer" == "B" ]; then mail –s "error log" boss< error.log; elif [ "$answer" == "c" –o "$answer" == "C" ]; then mail –s "Help! error log" –c denis nick < error.log; else echo "error"; exit; fi

У наступному топіці я продовжу розглядати керуючі структури командного інтерпретатора bash. Зокрема, будуть розглянуті оператори циклів. А зараз чекаю коментарів та критики:).

UPD: Дякуємо користувачу

При написанні сценаріїв на Bash не тільки досвідчені програмісти, а й новачки в командному інтерпретаторі Bash стикаються з роботою з рядками. Найчастіше це необхідно при зчитуванні команд, що вводяться користувачем як аргументи для сценарію, що виконується, а також при обробці текстових файлів. І один із необхідних прийомів у такому разі – це порівняння рядків.

У цій статті буде розглянуто порівняння рядків Bash, а також деякі нюанси щодо використання операцій порівняння і вирішення помилок, що часто зустрічаються.

Дані операції дозволяють визначити, чи порівнювані рядки однаковими:

  • = - Так само, наприклад if [ "$x" = "$y" ]
  • == - синонім оператора "=", наприклад if [ "$x" == "$y" ]
  • != - не однаково, наприклад if [ "$x" != "$y" ]

#!/bin/bash
testuser=anton
if [ $USER = $testuser ]
then
echo "Ласкаво просимо, $testuser"
fi

Результат роботи сценарію:

Під час перевірки на рівність за допомогою команди test(Синонім квадратним дужкам) враховуються всі пунктуаційні знаки та відмінності в регістрі літер порівнюваних рядків.

Деякі особливості порівняння рядків із шаблонами:

# повертає істину, якщо рядок, що міститься в $x, починається з символу "y"
[[ $x == y* ]]
# повертає істину, якщо рядок з $x дорівнює саме двом символам "y*"
[[ $x == "y*" ]]
# повертає істину, якщо $x містить назву файлу, що міститься в поточному каталозі, який починається з "y"
[ $x == y* ]
# повертає істину, якщо рядок $x дорівнює двом символам "y*"
[ "$x" == "y*" ]

Наприклад, перевірка рядка bash на те, чи починається вона з символу y:

#!/bin/bash
x=yandex
[[ $x == y* ]]
echo $?

Результат виконання коду:

Сценарій вивів 0 (нуль), оскільки ми вимагали вивести код помилки останньої виконаної інструкції. А код 0 означає, що сценарій виконався без помилок. І справді - змінна $xмістить рядок yandexяка починається з символу "y". В іншому випадку може писатися "1". Це досить зручний спосіб налагодження сценаріїв.

Порівняння рядків за алфавітом на Bash

Завдання ускладнюється при спробі визначити, чи є рядок попередницею іншого рядка у послідовності сортування за зростанням. Люди, які пишуть сценарії мовою командного інтерпретатора bash, нерідко стикаються з двома проблемами, що стосуються операцій "більше" і "менше" щодо порівняння рядків Linux, у яких досить прості рішення:

По-перше, символи "більше" та "менше" потрібно екранувати, додавши перед ними зворотний слеш (\), тому що в іншому випадку в командному інтерпретаторі вони будуть розцінюватися як символи перенаправлення, а рядки - як імена файлів. Це один із тих випадків, коли відстежити помилку досить складно.

#!/bin/bash
# неправильне використання операторів порівняння рядків
val1=baseball
val2=hockey
if [ $val1 > $val2 ]
then

else

fi

Що вийде, якщо порівняти рядки bash:

Як видно, лише символ "більше" у своєму безпосередньому вигляді привів до неправильних результатів, хоча і не було сформовано жодних помилок. В даному випадку цей символ привів до перенаправлення потоку виводу, тому жодних синтаксичних помилок не було виявлено і, як результат, створено файл з ім'ям hockey:

Для усунення цієї помилки потрібно екранувати символ ">", щоб умова виглядала так:

...
if [ $val1 \> $val2 ]
...

Тоді результат роботи програми буде правильним:

По-друге, рядки, що впорядковуються за допомогою операторів "більше" і "менше" розташовуються інакше, ніж це відбувається з командою sort. Тут проблеми складніше піддаються розпізнаванню, і з ними взагалі можна не зіткнутися, якщо при порівнянні не враховуватиметься регістр літер. В команді sortі testпорівняння відбувається по-різному:

#!/bin/bash
val1=Testing
val2=testing
if [ $val1 \> $val2 ]
then
echo "$val1 більше, ніж $val2"
else
echo "$val1 менше, ніж $val2"
fi

Результат роботи коду:

В команді testрядки з великими літерами спочатку передуватимуть рядкам із малими літерами. Але якщо ці дані записати у файл, до якого потім застосувати команду sort, то рядки з малими літерами будуть йти раніше:

Різниця їх роботи полягає в тому, що в testдля визначення порядку сортування за основу взято розташування символів таблиці ASCII. У sortвикористовується порядок сортування, вказаний для параметрів мови регіональних установок.

Перевірка рядка на порожнє значення

Порівняння за допомогою операторів -zі -nзастосовується визначення наявності вмісту в змінної. Таким чином, ви можете знайти порожні рядки bash. Приклад:

#!/bin/bash
val1=testing
val2=""
# перевіряє, чи не порожній рядок
if [ -n $val1 ]
then
echo "Рядок "$val1" не порожній"
else
echo "Рядок "$val1" порожній"
fi
# перевіряє, чи порожній рядок
if [ -z $val2 ]
then
echo "Рядок "$val2" порожній"
else
echo "Рядок "$val2" не порожній"
fi
if [ -z $val3 ]
then
echo "Рядок "$val3" порожній"
else
echo "Рядок "$val3" не порожній"
fi

Результат роботи коду:

У цьому прикладі створюються дві рядкові змінні - val1і val2. Операція -nвизначає, чи має змінна val1ненульову довжину, а -zперевіряє val2і val3на нульову. Примітно те, що остання не була визначена до моменту порівняння, але інтерпретатор вважає, що її довжина все ж таки дорівнює нулю. Такий нюанс слід враховувати під час різних перевірок сценаріїв. І якщо немає впевненості в тому, яке значення міститься в змінній і чи задано воно взагалі, варто перевірити її за допомогою оператора -nабо -zі лише потім використовувати за призначенням.

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

...
if [ -n "$val1" ]
...

Висновки

У поданих операціях порівняння рядків Bash є певні нюанси, які варто зрозуміти для запобігання помилкам роботи сценаріїв. Але таких ситуацій практично зустрічає багато, тому запам'ятати все (і тим більше, описати) не вийде.

 

 

Це цікаво: