ИТ Блог. Администрирование серверов на основе Linux (Ubuntu, Debian, CentOS, openSUSE)

Как написать сценарий безошибочной инструкции If в Bash?

Как написать сценарий безошибочной инструкции If в Bash?

Сценарий оболочки обычно должен проверить, выполняется ли команда успешно или выполняется условие. В Bash этот тест можно выполнить с помощью инструкции if в Bash. Как и в любом другом языке программирования, Bash поставляется с условными выражениями, которые позволяют вам проверять условия и изменять поток управления, если условие выполняется или нет.

В этом посте рассматривается оператор if в bash и связанные с ним предложения then, else if (elif) и else.

 

Введение в инструкцию If в Bash

В программировании оператор if – это условный оператор, также известный как условное выражение. Оператор if выполнит часть кода, если выполняется заданное условие. На него часто ссылаются как на оператор If-Then, If-Else или If-Then-Else. Оператор if всегда проверяет наличие логического условия для вычисления в true или false. Then, else if (elif) и else являются предложениями к оператору if.

 

Какой синтаксис инструкции If в Bash ?

В Bash оператор if является частью условных конструкций языка программирования. if в сценарии Bash – это ключевое слово оболочки Bash, которое используется для тестирования условий на основе состояния завершения тестовой команды. Нулевой статус завершения, и только нулевой, является успешным, то есть условием, которое является истинным. Любой другой статус завершения – это сбой, то есть условие, которое является ложным.

Синтаксис оператора if в Bash таков:

if first-test-commands; then
  consequent-commands;
[elif more-test-commands; then
  more-consequents;]
[else alternate-consequents;]
fi

 

Тестовые команды в инструкции if и предложениях elif выполняются по порядку, пока один тест не завершится успешно. Если ни один тест не завершается успешно, и предоставляется предложение else, то будет выполнена часть кода последнего предложения else.

 

Что такое двойные круглые скобки ((…)), одинарные […] и двойные [[..]] квадратные скобки?

Конструкции ((…)), […] и [[…]] часто используются для вычисления сложных условных выражений с помощью операторов сравнения и для возврата статуса завершения 0 или 1, который может быть использован в операторе if в bash.

Двойные круглые скобки ((…)) используются для проверки арифметического выражения. Вы можете прочитать больше об этой конструкции в нашем посте об арифметике bash. Он поддерживает двоичные операторы && и ||.

В одиночных квадратных скобках […] указана команда [, которая является встроенной оболочкой и псевдонимом команды test. Команда test и псевдоним [ используются для вычисления условных выражений. Это часть стандарта POSIX.

Существуют некоторые заметные различия между обозначениями в двойных и одинарных скобках:

 

Двойные квадратные скобки [[…]] – это ключевое слово оболочки. Оно похоже по поведению на одинарную квадратную скобку и используется для вычисления условных выражений и специфично для оболочек Bash, Zsh и Korn. Эта конструкция может обрабатывать более сложные условия и менее подвержена ошибкам.

Обратите внимание, что конструкции ((…)) и [[…]] являются составными командами Bash.

 

Что такое условные выражения Bash?

Условные выражения используются [[ составной командой и test и [ встроенными командами. Условные выражения могут быть унарными (один операнд) или двоичными (два операнда). Унарные операторы часто используются для проверки состояния файла, переменной, параметра оболочки (optname) или строки.

Унарные и двоичные выражения формируются со следующими первичными символами.

Условное выражение Значение
-a file Верно, если file существует.
-b file True if file существует и является специальным файлом для блоков.
-c file Верно, если file существует и является файлом со специальным символом.
-d file Верно, если file существует и является каталогом.
-e file Верно, если file существует.
-f file Верно, если file существует и является обычным файлом.
-g file Верно, если file существует и установлен бит set-group-id для него.
-h file True if file существует и является символической ссылкой.
-k file True, если file существует и установлен его бит “sticky”.
-p file True, если file существует и является именованным каналом (FIFO).
-r file True, если file  существует и доступен для чтения.
-s file True, если file существует и имеет размер больше нуля.
-t fd True, если дескриптор fd file открыт и ссылается на терминал.
-u file True, если file существует и установлен бит его идентификатора set-user-id.
-w file True, если file существует и доступен для записи.
-x file True, если file существует и является исполняемым.
-G file True, если file существует и принадлежит действующему идентификатору группы.
-L file True, если file существует и является символической ссылкой.
-N file True, если file существует и был изменен с момента его последнего чтения.
-O file True, если file существует и принадлежит действительному идентификатору пользователя.
-S file True, если file существует и является сокетом.
file1 -ef file2 Верно, если file1 и file2 относятся к одному и тому же устройству и номерам индексов.
file1 -nt file2 True, если file1  новее (в соответствии с датой модификации), чем file2, или если file1 существует, а file2 – нет.
файл1 -ot файл2 Верно, если file1 старше, чем file2, или если file2 существует, а file1 нет.
-o optname True, если включена опция оболочки optname (список опций см. set -o ).
-v varname True, если установлена переменная оболочки varname (было присвоено значение, даже пустое значение).
-R varname True, если переменная оболочки varname установлена и является ссылкой на имя.
-z string True, если длина string равна нулю.
-n string True, если длина string отлична от нуля.
string1 == string2
string1 = string2
True, если строки равны. Он будет выполнять сопоставление с шаблоном при использовании с командой [[ . =Обозначения должны использоваться с командой test для соответствия POSIX.
string1 != string2 True, если строки не равны.
string1 =~ regex True, если строки соответствуют Bash регулярному выражению regex. Захваченные группы хранятся в переменной массива BASH_REMATCH.
string1 < string2 True if string1  сортируется перед string2 лексикографически.
string1 > string2 True if string1  сортируется после string2 лексикографически.

 

Условные выражения также поддерживают арифметические двоичные операторы следующим образом, и где arg1 и arg2 являются либо положительными, либо отрицательными целыми числами. При использовании с командой [[ arg1 и arg2 вычисляются как арифметические выражения, следовательно, следует предпочесть составную команду ((.

Условное выражение Значение
arg1 -eq arg2 Верно, если arg1 равен arg2
arg1 -ne arg2 True, если arg1 не равен arg2
arg1 -lt arg2 True, если arg1 меньше, чем arg2
arg1 -le arg2 True, если arg1 меньше или равен arg2
arg1 -gt arg2 True, если arg1 больше, чем arg2
arg1 -ge arg2 True, если arg1 больше или равно arg2

 

Как использовать оператор If с предложениями Then, Else, Else If (elif)?

Как мы упоминали ранее, оператор If должен содержать предложение then и необязательно может содержать предложение else if с ключевым словом elif, за которым следует then, и/или предложение else. Оператор If всегда заканчивается ключевым словом fi.

Ключевые слова if, then, else, elif и fi должны быть последними ключевыми словами строки, иначе они должны заканчиваться точкой с запятой ; перед использованием любого другого ключевого слова.

if false; then
  echo 'This command will never run since condition is always false.';
elif ((RANDOM%2)); then
  echo 'This command will execute only when $RANDOM % 2 equal to 0.';
else
  echo 'This command will execute if no other condition is met.';
fi

 

Использование оператора If с условными выражениями

Обратите внимание, что для условия не требуются какие-либо специальные заключающие символы, такие как круглые скобки, хотя они могут использоваться для переопределения приоритета других операторов. В зависимости от выполняемого теста команда может быть использована напрямую, или с помощью [[ составной команды, или с помощью встроенных команд test и [. Составная команда (( зарезервирована для арифметического расширения. Пробелы между ключевыми словами и командами имеют значение.

Например, если мы хотим проверить, существует ли файл и является ли он обычным файлом (не символической ссылкой), мы могли бы использовать -f с любым из следующих обозначений.

[andreyex@linux ~]$ touch myfile
[andreyex@linux ~]$ if [[ -f myfile ]]; then echo "myfile exists. If Statement Condition equal $?."; fi
myfile exists. If Statement Condition equal 0.
[andreyex@linux ~]$ if [ -f myfile ]; then echo "myfile exists. If Statement Condition equal $?."; fi
myfile exists. If Statement Condition equal 0.
[andreyex@linux ~]$ if test -f myfile; then echo "myfile exists. If Statement Condition equal $?."; fi
myfile exists. If Statement Condition equal 0.

 

Вы можете отменить условие, используя ключевое слово !.

[andreyex@linux ~]$ rm myfile
[andreyex@linux ~]$ if [[ ! -f myfile ]]; then echo "myfile does not exist. If Statement Condition equal $?."; fi
myfile does not exist. If Statement Condition equal 0.

 

Использование инструкции if в bash с несколькими условиями

Как мы упоминали выше, вы можете использовать двоичные операторы && (и) и || (или) в составных обозначениях в двойных скобках [[. Это похоже на использование -a (и) и -o (или) в одной скобке.

[andreyex@linux ~]$ touch myfile
[andreyex@linux ~]$ if [[ -f myfile &&  -r myfile ]]; then echo "File exists and is Readable."; fi
File exists and is Readable.
[andreyex@linux ~]$ if [ -f myfile -a  -r myfile ]; then echo "File exists and is Readable."; fi
File exists and is Readable.
Обратите внимание, что если вы используете двоичные операторы в обозначении с одной скобкой, вы в конечном итоге получите ошибку bash: [: missing “]’. Это потому, что [ это команда и ожидание ] в качестве последнего аргумента. Аналогично, при использовании test команда завершится с ошибкой, bash: -r: command not found поскольку && завершается выполнение предыдущей команды, и сразу после этого ожидается новая команда. При использовании && or || с одиночными скобками вам нужно будет использовать их вне скобок или test команды.
[andreyex@linux ~]$ if [ -f myfile &&  -r myfile ]; then echo "File exists and is Readable."; fi
bash: [: missing `]'
[andreyex@linux ~]$ if [ -f myfile ] && [ -r myfile ]; then echo "File exists and is Readable."; fi
File exists and is Readable.
[andreyex@linux ~]$ if test -f myfile &&  -r myfile; then echo "File exists and is Readable."; fi
bash: -r: command not found
[andreyex@linux ~]$ if test -f myfile && test -r myfile; then echo "File exists and is Readable."; fi
File exists and is Readable.

Использование вложенных инструкций If

Вложенный оператор if – это оператор if внутри предложения другого оператора if. Ничто не препятствует использованию нескольких уровней оператора if в сценарии оболочки и в Bash.

if first-test-commands; then
  if second-level-test-commands; then
    consequent-commands;
  else second-level-alternate-consequents;
[elif more-test-commands; then
  more-consequents;]
[else alternate-consequents;]
fi

 

Распространенные подводные камни и ошибки

Неправильное использование команды с одной скобкой [

Одна из наиболее распространенных ошибок, связанных с командой командной оболочки [, заключается в неправильном использовании кавычек в условном выражении. Строковые литералы не обязательно заключать в кавычки с условием [ or test, если только они не содержат подстановочных знаков.

Первый аргумент условия должен быть заключен в кавычки, если он является переменной. При неправильном использовании вы столкнетесь с ошибкой bash bash: [: too many arguments.

[andreyex@linux ~]$ myVar="a b"

# НЕПРАВИЛЬНО
[andreyex@linux ~]$ [ $myVar = "a b" ]; echo $?
bash: [: too many arguments
2

# ПРАВИЛЬНО
[andreyex@linux ~]$ [ "$myVar" = "a b" ]; echo $?
0

 

Еще одна ошибка заключается в неправильном использовании пробелов в команде [. Как мы обсуждали ранее в этом посте, конструкция [ – это встроенная команда оболочки, похожая на команду test. Таким образом, после имени команды должен быть пробел перед первым аргументом, и каждый аргумент, включая операторы сравнения, должен содержать пробелы.

[andreyex@linux ~]$ var="Example String"

# НЕПРАВИЛЬНО: отсутствие пробела вокруг команды `[` приведет к ошибке bash "команда не найдена"
[andreyex@linux ~]$ if [string="$var"]; then echo ${var}; fi
bash: [string=]: command not found

# НЕПРАВИЛЬНО: Пропущенный пробел вокруг оператора приведет к ошибочному возвращению выражения как true
[andreyex@linux ~]$ if [ string="$var" ]; then echo ${var}; fi
Example String

# ПРАВИЛЬНОЕ использование пробелов с помощью команды [
[andreyex@linux ~]$ if [ string = "$var" ]; then echo ${var}; fi
Наконец, частой ошибкой [ команды является использование двоичного оператора && or || внутри скобок, что неверно по той же причине, что и выше. [ это команда, в которой должен быть последний аргумент ]. Операторы && и || нарушают это условие и приведут к ошибке bash bash: [: missing “]’.
[andreyex@linux ~]$ a=b; c=d;

# НЕПРАВИЛЬНОЕ использование &&
[andreyex@linux ~]$ if [ $a = b && $c = d ]; then echo "Success"; fi
bash: [: missing `]'

# ПРАВИЛЬНОЕ использование &&
[andreyex@linux ~]$ if [ $a = b ] && [ $c = d ]; then echo "Success"; fi
Success

 

Как решить ожидаемую ошибку двоичного оператора?

Причина ошибки Bash binary operator expected обычно заключается в том, что переменная расширяется до нескольких слов и неправильно заключена в кавычки при использовании с командой test or [. Если вам не требуется, чтобы ваш скрипт был на 100% совместим с POSIX, лучшей альтернативой является использование встроенной команды [[ в bash, на которую не повлияет разделение слов или расширение глобуса.

[andreyex@linux ~]$ string="word1 word2"

# НЕВЕРНО: Пропущенные кавычки
[andreyex@linux ~]$ if [ -n $string ]; then echo "\$string length >0"; fi
bash: [: word1: binary operator expected

# ПРАВИЛЬНО
[andreyex@linux ~]$ if [ -n "$string" ]; then echo "\$string length >0"; fi
$string length >0

# ПРАВИЛЬНО и лучше в bash
[andreyex@linux ~]$ if [[ -n $string ]]; then echo "\$string length >0"; fi
$string length >0

 

Почему вы не должны использовать операторы || и && вместо инструкции if в bash?

Попытка эмулировать троичный оператор с помощью двоичных операторов || (или) и && (и) может привести к ошибкам и неожиданным результатам. По возможности предпочитайте обычные конструкции инструкции if. Основная проблема заключается в том, что команда && также будет генерировать статус завершения и может привести к тому, что команда после || будет выполнена.

# Неверно/Не рекомендуется
[[ ! -f myFile ]] && myCommandOnSuccess || myCommandOnFailure

# Правильная/наилучшая практика
if [[ -f myFile ]]; then
  myCommandOnSuccess
else
  myCommandOnFailure
fi

# НЕПРАВИЛЬНО: все команды выполнены
[andreyex@linux ~]$ [[ ! -f myFile ]] && { echo "File not found"; false; } || { echo "File exist"; true; }
File not found
File exist

# НЕПРАВИЛЬНО: все арифметические разложения выполняются и возвращают неверное значение z
[andreyex@linux ~]$ z=0; [[ -v z ]] && ((z++)) || ((z--)); echo $z
0
# ИСПРАВИТЬ, если в инструкции bash используется
[andreyex@linux ~]$ z=0; if [[ -v z ]]; then ((z++)); else ((z--)); fi; echo $z
1

# КОРРЕКТНО только для арифметических расширений и не может использовать -v
[andreyex@linux ~]$ z=0; (( z==0 ? z++ : z-- )); echo $z
0

 

Подробные примеры и часто задаваемые вопросы

Ниже приведены некоторые распространенные примеры и варианты использования инструкции if и условных выражений в Bash.

 

Как проверить, существует ли переменная или она равна “null”?

Для проверки того, существует ли переменная или имеет значение null, в Bash можно использовать три основных выражения условного выражения: -v, -n и -z.

👉 В оболочке Bash нет определения переменной null. Мы будем говорить либо о том, установлена переменная, либо о том, что она не установлена. Обратите внимание, что переменная может быть задана с пустой строкой (строка нулевой длины с использованием двойных кавычек “”) или без значения, которое может быть указано как нулевое значение. Эту терминологию не следует путать с командой Null в Bash, которая имеет совершенно другое назначение.

-v можно использовать для проверки, установлена ли переменная оболочки. Обратите внимание, что в качестве параметра он принимает имя переменной, т.е. без знака $. Если для переменной задано пустое значение или нулевая длина, условие вернет значение true (код выхода 0).
# Переменная не существует
[andreyex@linux ~]$ [[ -v myVar ]] ; echo "Condition returned $?"
Condition returned 1

# Переменная установлена и существует
[andreyex@linux ~]$ myVar="test"
[andreyex@linux ~]$ [[ -v myVar ]] ; echo "Condition returned $?"
Condition returned 0

# Переменная имеет значение строки нулевой длины (null/empty) и существует
[andreyex@linux ~]$ myVar=
[andreyex@linux ~]$ [[ -v myVar ]] ; echo "Condition returned $?"
Condition returned 0

# Переменная не установлена и не существует
[andreyex@linux ~]$ unset myVar
[andreyex@linux ~]$ [[ -v myVar ]] ; echo "Condition returned $?"
Condition returned 1

 

-n и -z также будут проверять длину строки. Параметр -n проверяет ненулевую длину, а параметр  -z проверяет строку нулевой длины. Эти первичные параметры могут быть полезны, если вы намерены проверить, является ли переменная пустой или нет. Однако будьте осторожны, если ваш сценарий оболочки выполняется с опцией set -u, а ваша переменная не существует, тогда ваш сценарий завершится с ошибкой типа bash: myVar: unbound variable.

Чтобы обойти это, вы можете протестировать с расширением параметра, используя ${parameter:+word}, чтобы убедиться, что переменная установлена. Вы также можете комбинировать использование -v и -z, таких как [[ -v varName && -z $varName ]]. Я нахожу последнюю структуру более понятной, поскольку она переводится в “если моя переменная существует, а длина моей переменной равна нулю (-z) / ненулевому значению (-n), то …”, хотя это несколько иное поведение, чем просто использование решения для расширения параметров.

[andreyex@linux ~]$ unset myVar

# Проверка на переменную длины, превышающую ноль, при отключенном myVar
[andreyex@linux ~]$ [[ -z $myVar ]] ; echo "Condition returned $?"
Condition returned 0

# Проверка на переменную длину, равную нулю, при отключенном myVar
[andreyex@linux ~]$ [[ -n $myVar ]] ; echo "Condition returned $?"
Condition returned 1

# Тест на переменную длину с набором myVar
[andreyex@linux ~]$ myVar="test"
[andreyex@linux ~]$ [[ -z $myVar ]] ; echo "Condition returned $?"
Condition returned 1
[andreyex@linux ~]$ [[ -n $myVar ]] ; echo "Condition returned $?"
Condition returned 0

# НЕКОРРЕКТНЫЙ тест для переменной длины с параметром set -u и расширением параметров
[andreyex@linux ~]$ unset myVar ; set -u
[andreyex@linux ~]$ [[ -z $myVar ]] ; echo "Condition returned $?"
bash: myVar: unbound variable

# КОРРЕКТНЫЕ тесты с не заданной переменной
[andreyex@linux ~]$ unset myVar ; set -u
[andreyex@linux ~]$ [[ -z ${myVar:+x} ]] ; echo "Condition returned $?"
Condition returned 0
[andreyex@linux ~]$ [[ -n ${myVar:+x} ]] ; echo "Condition returned $?"
Condition returned 1

# ИСПРАВЬТЕ, если вы считаете, что неустановленная переменная не совпадает с переменной нулевой длины
# Условие возвращает "False" в обоих случаях
[andreyex@linux ~]$ [[ -v myVar && -z $myVar ]] ; echo "Condition returned $?"
Condition returned 1
[andreyex@linux ~]$ [[ -v myVar && -n $myVar ]] ; echo "Condition returned $?"
Condition returned 1

# КОРРЕКТНЫЕ тесты с пустой переменной
[andreyex@linux ~]$ myVar="" ; set -u
[andreyex@linux ~]$ [[ -v myVar && -z $myVar ]] ; echo "Condition returned $?"
Condition returned 0
[andreyex@linux ~]$ [[ -z ${myVar:+x} ]] ; echo "Condition returned $?"
Condition returned 1
[andreyex@linux ~]$ [[ -v myVar && -n $myVar ]] ; echo "Condition returned $?"
Condition returned 1
[andreyex@linux ~]$ [[ -n ${myVar:+x} ]] ; echo "Condition returned $?"
Condition returned 1

# КОРРЕКТНЫЕ тесты с непустой переменной
[andreyex@linux ~]$ myVar="test"
[andreyex@linux ~]$ [[ -v myVar && -z $myVar ]] ; echo "Condition returned $?"
1
[andreyex@linux ~]$ [[ -z ${myVar:+x} ]] ; echo "Condition returned $?"
Condition returned 1
[andreyex@linux ~]$ [[ -v myVar && -n $myVar ]] ; echo "Condition returned $?"
Condition returned 0
[andreyex@linux ~]$ [[ -n ${myVar:+x} ]] ; echo "Condition returned $?"
Condition returned 0

 

Вы можете использовать выражение в одной скобке с этими основными параметрами, но вам нужно обязательно заключать переменную в кавычки при проверке длины строки с помощью -z и -n, чтобы предотвратить разделение слов или расширение глобуса. Двойные скобки в кавычках не нужны, поскольку это поведение по умолчанию.

 

Как проверить, существует ли файл?

-f Primary можно использовать для проверки, существует ли обычный файл или нет.

[andreyex@linux ~]$ touch myfile
[andreyex@linux ~]$ if [[ -f myfile ]]; then echo "myfile exists. If Statement Condition equal $?."; fi
myfile exists. If Statement Condition equal 0.
[andreyex@linux ~]$ if [ -f myfile ]; then echo "myfile exists. If Statement Condition equal $?."; fi
myfile exists. If Statement Condition equal 0.
[andreyex@linux ~]$ if test -f myfile; then echo "myfile exists. If Statement Condition equal $?."; fi
myfile exists. If Statement Condition equal 0.

 

Помните, что условные выражения будут следовать символическим ссылкам при тестировании файлов и будут выполнять тест для целевого объекта ссылки. Следовательно, тест вернет 1 (false)), когда символические ссылки указывают на несуществующий файл или если у вас нет надлежащего разрешения на доступ к целевому файлу. Чтобы проверить, существует ли обычный файл или соответствующие символические ссылки, можно было бы протестировать с объединением -f и -L первичных файлов.

[andreyex@linux ~]$ touch myfile ; ln -s broken_target broken_link

# протестируйте с помощью -f обычный файл и неработающую символическую ссылку
[andreyex@linux ~]$ [[ -f myfile ]]; echo $?
0
[andreyex@linux ~]$ [[ -f broken_link ]]; echo $?
1

# протестируйте с помощью -L обычный файл и неработающую символическую ссылку
[andreyex@linux ~]$ [[ -L myfile ]]; echo $?
1
[andreyex@linux ~]$ [[ -L broken_link ]]; echo $?
0

# Комбинированный тест на наличие файла или символической ссылки
[andreyex@linux ~]$ [[ -f broken_link || -L broken_link ]]; echo $?
0

 

Как проверить, существует ли каталог?

-d Primary можно использовать для проверки того, существует каталог или нет.

[andreyex@linux ~]$ mkdir myDir
[andreyex@linux ~]$ if [[ -d myDir ]]; then echo "myDir exists. If Statement Condition equal $?."; fi
myDir exists. If Statement Condition equal 0.
[andreyex@linux ~]$ if [ -d myDir ]; then echo "myDir exists. If Statement Condition equal $?."; fi
myDir exists. If Statement Condition equal 0.
[andreyex@linux ~]$ if test -d myDir; then echo "myDir exists. If Statement Condition equal $?."; fi
myDir exists. If Statement Condition equal 0.

 

Как проверить, выполнена команда успешно или сбой?

Инструкция if в bash принимает команду и проверяет код завершения этой команды, используя синтаксис if <command>; then <code>; fi.

Если вы не собираетесь использовать значение кода выхода вашей команды, не используйте код состояния выхода с помощью $?, это не нужно и может привести к ошибкам при использовании с set -e.

# КОРРЕКТНО
[andreyex@linux ~]$ if grep -q RegPattern "$myfile"; then
  echo "Found RegPattern in $myfile"
fi

# НЕ РЕКОМЕНДУЕТСЯ
[andreyex@linux ~]$ grep -q RegPattern "$myfile"
[andreyex@linux ~]$ if [ $? -eq 0 ]; then echo "Found RegPattern in $myfile"; fi

 

Как выполнить сравнение строк и проверить, равна ли строка значению?

При использовании [[оператор== можно использовать для проверки равенства строк в Bash. Помните, что [[…]] составная команда выполнит сопоставление с шаблоном, где правая сторона может быть шаблоном глобуса. Следовательно, чтобы предотвратить глобализацию и проверить равенство строк, обязательно заключите правую часть условного выражения в кавычки.

👉 Подробнее о глобировании и шаблонах глобуса читайте в моем посте о том, как использовать подстановочные знаки Bash для глобирования.

 

[andreyex@linux ~]$ myString1=abc ; myString2=ab*

# Без кавычек Bash выполнит шаблон glob и не сможет должным образом проверить равенство
[andreyex@linux ~]$ [[ $myString1 == $myString2 ]]; echo $?
0
[andreyex@linux ~]$ [[ $myString1 == "$myString2" ]]; echo $?
1

# Исправьте проверку на равенство строк с помощью оператора if в bash
[andreyex@linux ~]$ if [[ $myString1 == "$myString2" ]]; then
  echo "\$myString1 equals to \$myString2 with the string: $myString1";
else
  echo "\$myString1 and \$myString2 are different with \$myString1=$myString1 and \$myString2=$myString2";
fi

 

Если ваш сценарий оболочки требует соответствия POSIX, вам нужно будет протестировать с помощью команд test or [ и использовать оператор =. Кавычки становятся неактуальными в тех случаях, когда test и [ не выполняют глобализацию.

Если вы хотите протестировать строки на соответствие регулярному выражению, вам нужно будет использовать =~ оператор и сначала определить регулярное выражение, поскольку использование кавычек приведет к тому, что ваше регулярное выражение будет обрабатываться как строка.

[andreyex@linux ~]$ myString="ab c" ; myRegex='[[:alpha:]]+.*'
# Проверьте строку на соответствие шаблону регулярных выражений
[andreyex@linux ~]$ [[ $myString =~ $myRegex ]]; echo $?
0

# Это завершилось бы неудачей, поскольку оно проверялось на соответствие строковому значению регулярного выражения
[andreyex@linux ~]$ [[ $myString =~ "$myRegex" ]]; echo $?
1

 

Как проверить, находится ли строка в массиве?

Для поиска точного соответствия вашему regex шаблону необходимо добавить дополнительные пробелы перед и после значения like (^|[[:space:]])”VALUE”($|[[:space:]]).

[andreyex@linux ~]$ declare -A myAssociativeArray; myAssociativeArray=([a]=123 [b]=456)
[andreyex@linux ~]$ [[ ${myAssociativeArray[*]} =~ (^|[[:space:]])"12"($|[[:space:]]) ]] ; echo $?
1
[andreyex@linux ~]$ [[ ${myAssociativeArray[*]} =~ (^|[[:space:]])"123"($|[[:space:]]) ]] ; echo $?
0

 

Смотрите подробные примеры в посте: массивы в Bash.

 

Как использовать троичный оператор Bash?

В Bash нет тернарного оператора, хотя при использовании арифметического расширения ((…)) конструкция в двойных круглых скобках поддерживает вопросительный знак ? как элемент тернарного (или тройного) оператора в стиле C, например (( condition ? result-if-true : result-if-false )). На мой взгляд, он имеет ограниченный вариант использования, поскольку в большинстве случаев было бы более уместно просто проверить условие, используя стандартный возвращаемый код выхода 0 or 1.

[andreyex@linux ~]$ myVar=12 ; echo $((myVar>10?true:false)) ; echo $((myVar>10?17:3))
0
17

 

Использование операторов && и || для эмуляции троичного оператора в сценарии оболочки не рекомендуется, поскольку это чревато ошибками, см. Раздел ниже о почему вы не должны использовать операторы || и && вместо инструкции if в bash.

 

Как отменить условие if в операторе if в bash? (если не команда или если не равно)

Чтобы отменить любое условие, используйте оператор !, например: if ! <test-command>; then <command-on-failure>; fi. Обратите внимание, что пробел между ! и следующей командой важен, в противном случае она выполнила бы расширение bash history и, скорее всего, вернула бы ошибку bash event not found.

Для сравнения строк в условном выражении можно использовать оператор not equal !=, например, string1 != string2.

Ниже приведен пример отрицательного условия для команды grep.

if ! grep -q lookupWord "$myFile"; then
  echo 'Failed to grep';
fi

 

Как использовать переменную BASH_REMATCH с оператором регулярного выражения =~?

Условный оператор регулярного выражения =~ принимает строковое значение в левой части и расширенное регулярное выражение Bash в правой части оператора. Синтаксис: *string1* =~ *regex*. Оператор возвращает код выхода 0 (True), если строки соответствуют регулярному выражению regex.

Переменная $BASH_REMATCH – это массив Bash=~, доступный только для чтения, содержащий значения, сопоставленные расширенному регулярному выражению в правой части [[ двоичного оператора в условном выражении с двойными скобками, заключенном в две скобки. Захваченные группы хранятся в переменной массива BASH_REMATCH. Строке, соответствующей всему регулярному выражению, присваивается первый индекс (0) массива. Следующие элементы в массиве с индексом n соответствуют строке, соответствующей n-му подвыражению, заключенному в скобки.

[andreyex@linux ~]$ shopt -s extglob
[andreyex@linux ~]$ var="This is An Example of Bash Extended Regular Expression"
[andreyex@linux ~]$ [[ "$var" =~ Regular ]] && echo "Word 'Regular' found. BASH_REMATCH=${BASH_REMATCH[@]}"
Word 'Regular' found. BASH_REMATCH=Regular
[andreyex@linux ~]$ [[ "$var" =~ (a) ]] && echo "Letter 'a' found. BASH_REMATCH=${BASH_REMATCH[@]}"
Exit mobile version