Bash if сравнение строк. Условие if-else BASH

Данный топик является четвертым топиком цикла «Язык командного интерпретатора 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" read answer case $answer in b|B) mail –s "error log" boss < 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 необходимо использовать состояние “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 не только опытные программисты, но и новички в области командного интерпретатора 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 есть определённые нюансы, которые стоит понять для предотвращения ошибок работы сценариев. Но таких ситуаций на практике встречает много, поэтому запомнить все (и тем более, описать) не получится.

Сравнение строк в 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 .

Условие 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

Понравилась статья? Поделиться с друзьями: