При написании сценариев на Bash не только опытные программисты, но и новички в области командного интерпретатора Bash сталкиваются с работой со строками. Наиболее часто это необходимо при считывании команд, вводимых пользователем в качестве аргументов для исполняемого сценария, а также при обработке текстовых файлов. И один из необходимых приёмов в таком случае — это сравнение строк.
В данной статье будет рассмотрено сравнение строк Bash, а также некоторые нюансы по использованию операций сравнения и решению часто встречающихся ошибок.
Содержание статьи
Сравнение строк Bash
Данные операции позволяют определить, являются ли сравниваемые строки одинаковыми:
- = - равно, например if [ "$x" = "$y" ]
- == - синоним оператора "=", например if [ "$x" == "$y" ]
- != - не равно, например if [ "$x" != "$y" ]
Пример:
Результат работы сценария:
При проверке на равенство с помощью команды test (синоним квадратным скобкам [ ]) учитываются все пунктуационные знаки и различия в регистре букв сравниваемых строк.
Некоторые особенности сравнения строк с шаблонами:
Например проверка строки bash на то, начинается ли она с символа y:
Результат выполнения кода:
Сценарий вывел 0 (ноль), так как мы потребовали вывести код ошибки последней выполненной инструкции. А код 0 означает, что сценарий выполнился без ошибок. И действительно — переменная $x содержит строку yandex, которая начинается с символа "y". В противном случае может писаться "1". Это довольно удобный способ отладки сценариев.
Сравнение строк по алфавиту на Bash
Задача усложняется при попытке определить, является ли строка предшественницей другой строки в последовательности сортировки по возрастанию. Люди, пишущие сценарии на языке командного интерпретатора bash, нередко сталкиваются с двумя проблемами, касающимися операций "больше" и "меньше" относительно сравнения строк Linux, у которых достаточно простые решения:
Во-первых, символы "больше" и "меньше" нужно экранировать, добавив перед ними обратный слэш (\), потому что в противном случае в командном интерпретаторе они будут расцениваться как символы перенаправления, а строки — как имена файлов. Это один из тех случаев, когда отследить ошибку достаточно сложно.
Пример:
Что получится, если сравнить строки bash:
Как видно, один лишь символ "больше" в своём непосредственном виде привёл к неправильным результатам, хотя и не было сформировано никаких ошибок. В данном случае этот символ привёл к перенаправлению потока вывода, поэтому никаких синтаксических ошибок не было обнаружено и, как результат, был создан файл с именем hockey:
Для устранения этой ошибки нужно экранировать символ ">", чтобы условие выглядело следующим образом:
Тогда результат работы программы будет правильным:
Во-вторых, упорядочиваемые с помощью операторов "больше" и "меньше" строки располагаются иначе, чем это происходит с командой sort. Здесь проблемы сложнее поддаются распознаванию, и с ними вообще можно не столкнуться, если при сравнении не будет учитываться регистр букв. В команде sort и test сравнение происходит по разному:
Результат работы кода:
В команде test строки с прописными буквами вначале будут предшествовать строкам со строчными буквами. Но если эти же данные записать в файл, к которому потом применить команду sort, то строки со строчными буквами будут идти раньше:
Разница их работы заключается в том, что в test для определения порядка сортировки за основу взято расположение символов по таблице ASCII. В sort же используется порядок сортировки, указанный для параметров языка региональных установок.
Проверка строки на пустое значение
Сравнение с помощью операторов -z и -n применяется для определения наличия содержимого в переменной. Таким образом, вы можете найти пустые строки bash. Пример:
Результат работы кода:
В этом примере создаются две строковые переменные — val1 и val2. Операция -n определяет, имеет ли переменная val1 ненулевую длину, а -z проверяет val2 и val3 на нулевую. Примечательно то, что последняя не была определена до момента сравнения, но интерпретатор считает, что её длина всё же равна нулю. Такой нюанс следует учитывать при различных проверках сценариев. И, если нет уверенности в том, какое значение содержится в переменной и задано ли оно вообще, стоит проверить её с помощью оператора -n или -z и лишь затем использовать по назначению.
Стоит обратить внимание и на функцию -n. Если ей для проверки будет передана необъявленная или пустая переменная, будет возвращена истина, а не ложь. Для таких случаев следует заключать проверяемую строку (переменную) в двойные кавычки, чтобы выглядело это так:
Выводы
В представленных операциях сравнения строк Bash есть определённые нюансы, которые стоит понять для предотвращения ошибок работы сценариев. Но таких ситуаций на практике встречает много, поэтому запомнить все (и тем более, описать) не получится.
При сравнении строк в виде переменных их можно заключать в кавычки практически всегда, так как это считается правилом хорошего тона, а заодно и страхует от семантических ошибок.
Всегда говорил, что программирующие на BASH - героические люди. Так и не нашёл времени его как следует освоить только потому, что сегодня почти в любом Лине уже в дефолте найдутся Python или Perl. Тем не менее статьи подобные этой мотивируют избавиться от комплекса неполноценности и научиться наконец-то писать и на BASH.
Кста... если кому интересно, кратко о работе со строками в Питоне: http://auriz.ru/NSLiDiN
Проверка строки на пустое значение:
if [ "$val1" ]
then
echo "Строка '$val1' не пустая"
else
echo "Строка '$val1' пустая"
fi
Всё верно. Просто для наглядности написано с применением опции
Насколько помню: = и == не совсем синонимы...один сравнивает коды символов, другой значения, для строк было бы, наверное, корректнее использовать =, а == оставить числовым значениям.
С кавычками вокруг переменных тоже не всё гладко, даже в двойных скобках: стоит только появиться пробелу или табуляции (или ещё чего) в сравниваемом и сравнение накрывается медным тазом...но в то же время кавычки не позволяют в полной мере использовать регулярки, типа вашего y*
Ну, и не мешало бы добавить разницу одинарных [] и двойных [[]] скобок, а также примеров, аля: [[ "$x" = 'hello world' || "$x" = 'сам такой' ]] && echo 'Свершилось чудо :D'
$ if ['a' = 'b'] then echo 'equal' else echo 'not equal' fi
> bash: syntax error: unexpected end of file
Что я не так пишу?
И как отредактировать или удалить ошибочный комментарий?
Одиночная кавычка и двойная кавычка - это разница!
Не понял почему при экранировании символа > вывелось: baseball меньше чем hockey. Ведь в слове baseball - 8 символов, а в слове hockey - 6
#!/bin/bash
val1=baseball
val2=hockey
if [ $val1 \> $val2 ]
then
echo "$val1 больше, чем $val2"
else
echo "$val1 меньше, чем $val2"
fi
Потому что буква b идет перед буквой h в альфавите. Сравнение идет побуквенно