Условия в сценариях bash (операторы if)

Если вы используете bash для написания сценариев, вам, несомненно, придется часто использовать условия, например, для конструкции if ... then или цикла while. Синтаксис этих условий может показаться немного сложным для изучения и использования. Цель этого руководства - помочь понять условия в bash и предоставить полный список возможностей.

Что такое сценарии Bash?

Прежде чем начать, давайте убедимся, что мы все на одной странице. Что такое сценарии Bash? Простой способ представить себе сценарии Bash - думать о них как о сценариях фильмов. Они говорят актерам, что говорить в определенное время, верно? Так вот, сценарии Bash указывают Bash, что делать в определенное время.

Сценарии Bash - это простой текстовый файл, содержащий серию команд, которые мы хотим автоматизировать, а не выполнять вручную.

Следует помнить одну вещь, о которой легко забыть: При написании собственного сценария Bash нужно не забыть установить бит execute на файл, прежде чем мы попытаемся настроить сценарий.

Общие специальные символы, используемые в Bash

  • " " или ' ' - Обозначает пробелы. Одинарные кавычки сохраняют буквальное значение; двойные кавычки позволяют делать замены.
  • $ - Обозначает расширение (для использования с переменными, подстановки команд, арифметической подстановки и т.д.).
  • \ - Эскейп-символ. Используется для удаления "особенности" специального символа.
  • # - Комментарии. Все, что после этого символа, не интерпретируется.
  • = - Задание значения
  • [ ] или [[ ]] - Тест; оценивает истинность или ложность
  • ! - Отрицание
  • >>, >, < - Перенаправление ввода/вывода
  • | - Направляет выход одной команды на вход другой.
  • * или ? - подстановочные знаки. ? - это подстановочный знак для одного символа.

Введение в программирование Bash

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

Условие в этом примере - это, по сути, команда. Это может показаться странным, но окружение сравнения квадратными скобками - это то же самое, что использование встроенной команды test, например, так:

Если $foo больше или равно 3, то будет выполнен блок после 'then'. Если вы всегда задавались вопросом, почему bash использует -ge или -eq вместо >= или ==, то это потому, что этот тип условия происходит от команды, где -ge и -eq являются опциями.

И это то, что по сути делает if - проверяет статус выхода команды. Существуют также встроенные проверки, которые более специфичны для shell'ов. Как насчет этой?

Приведенное выше условие верно, если файл 'file' существует и является обычным файлом. Обычный файл означает, что он не является блочным или символьным устройством, или каталогом. Таким образом, вы можете убедиться в существовании пригодного для использования файла, прежде чем что-то с ним делать. Вы даже можете проверить, доступен ли файл для чтения!

Приведенное выше условие верно, если файл 'file' существует и доступен для чтения.

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

Основной синтаксис оператора if ... then выглядит следующим образом:

Условие, в зависимости от его типа, окружено определенными скобками, например [ ]. Вы можете добавить команды, которые будут выполняться, если условие ложно, используя ключевое слово else, и использовать ключевое слово elif (elseif) для выполнения команд по другому условию, если основное условие ложно. Ключевое слово else всегда идет последним. Пример:

Краткое объяснение примера: сначала мы проверяем, доступен ли файл somefile для чтения ("if [ -r somefile ]"). Если да, то мы читаем его в переменную. Если нет, проверяем, существует ли он на самом деле ("elif [ -f somefile ]"). Если это так, мы сообщаем, что он существует, но не доступен для чтения (если бы он существовал, мы бы прочитали его содержимое). Если файл не существует, мы тоже сообщаем об этом. Условие в elif выполняется только в том случае, если условие в if было ложным. Команды, принадлежащие else, выполняются только в том случае, если оба условия ложны.

Основные правила написания условий в bash

Когда вы начинаете писать и использовать свои собственные условия, необходимо знать некоторые правила, чтобы избежать ошибок, которые трудно отследить. Ниже приведены три важных из них:

Всегда оставляйте пробелы между скобками и фактической проверкой/сравнением. Следующее не сработает:

Bash будет жаловаться на "отсутствующий" ]

Всегда заканчивайте строку перед тем, как вставить новое ключевое слово типа "then". Слова if, then, else, elif и fi являются ключевыми словами оболочки, что означает, что они не могут находиться в одной строке. Поставьте ";" между предыдущим оператором и ключевым словом или поместите ключевое слово в начало новой строки. В противном случае Bash будет выдавать ошибки типа "syntax error near unexpected token `fi'".

Хорошая привычка - заключать строковые переменные в кавычки, если вы используете их в условиях, потому что в противном случае они могут вызвать проблемы, если содержат пробелы и/или новые строки. Под кавычками я подразумеваю:

Есть несколько случаев, когда не следует использовать кавычки, но они редки.

Кроме того, есть две вещи, которые может быть полезно знать:

Вы можете инвертировать условие, поставив перед ним знак "!". Пример:

Обязательно поместите "!" внутрь скобок!

Вы можете комбинировать условия, используя определенные операторы. Для синтаксиса с одной скобкой, который мы использовали до сих пор, вы можете использовать "-a" для and и "-o" для or. Пример:

Приведенное выше условие вернет истину, если $foo содержит целое число больше или равно 3 и меньше 10.

И еще один важный момент: не забывайте, что условия можно использовать и в других операторах, таких как while и until.

В любом случае, до сих пор я показывал вам только условия между одинарными скобками. Однако есть и другие синтаксисы, о которых вы прочтете в следующем разделе.

Различные синтаксисы условий

Bash имеет различные синтаксисы для условий.

Синтаксис с одной скобкой

Это синтаксис условий, который вы уже видели в предыдущих параграфах; это самый старый поддерживаемый синтаксис. Он поддерживает три типа условий:

Условия на основе файлов

Позволяет выполнять различные виды проверок файла. Пример:

Приведенное выше условие истинно, если файл "symboliclink" существует и является символической ссылкой. Дополнительные условия на основе файлов см. в таблице ниже.

Условия на основе строк

Позволяет проверять строку и сравнивать строки. Пример первый:

Приведенное выше условие истинно, если $emptystring - пустая строка или неинициализированная переменная. Пример второй:

Приведенное выше условие истинно, если $stringvar1 содержит только строку "cheese". Другие условия, основанные на строках, приведены в таблице ниже.

Арифметические (основанные на числах) условия

Позволяет сравнивать целые числа. Пример:

Приведенное выше условие возвращает true, если $num меньше 1.

Синтаксис двойных квадратных скобок

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

Синтаксис двойных скобок является расширенной версией синтаксиса одинарных скобок; в основном он имеет те же возможности, но есть и некоторые важные отличия от него. Я перечислю их здесь:

Первое отличие видно из приведенного выше примера: при сравнении строк в синтаксисе двойных скобок используется оболочка globbing. Это означает, что звездочка ("*") будет расширяться буквально до всего, как вы, вероятно, знаете из обычного использования командной строки. Поэтому, если $stringvar содержит фразу "string" где-либо, условие вернет true. Допустимы и другие формы расширения оболочки. Если вы хотите найти и "String", и "string", вы можете использовать следующий синтаксис:

Обратите внимание, что разрешено только общее сплетение оболочки. Bash-специфические вещи, такие как {1..4} или {foo,bar} не будут работать. Также обратите внимание, что глобализация не будет работать, если вы заключите нужную строку в кавычки. В этом случае ее следует оставить без кавычек.

Второе отличие заключается в том, что разделение слов предотвращается. Поэтому можно не ставить кавычки вокруг строковых переменных и без проблем использовать условие, подобное следующему:

Тем не менее, заключение строковых переменных в кавычки остается хорошей привычкой, поэтому я рекомендую просто продолжать это делать.
Третье отличие заключается в том, что имена файлов не расширяются. Я проиллюстрирую это различие на двух примерах, начиная со старой ситуации с одинарными скобками:

Приведенное выше условие вернет true, если в рабочем каталоге есть один единственный файл с расширением .sh. Если их нет, то будет возвращено false. Если файлов .sh несколько, bash выдаст ошибку и прекратит выполнение сценария. Это происходит потому, что *.sh расширяется до файлов в рабочем каталоге. Использование двойных скобок предотвращает это:

Приведенное выше условие вернет истину только в том случае, если в рабочем каталоге есть файл с именем "*.sh", независимо от того, какие еще файлы .sh существуют. Звездочка воспринимается буквально, поскольку синтаксис двойных скобок не расширяет имена файлов.
Четвертое отличие - добавление более известных комбинированных выражений, или, более конкретно, операторов "&&" и "||". Пример:

Приведенное выше условие возвращает true, если $num равно 3 и $stringvar равно "foo". Также поддерживаются -a и -o, известные по синтаксису одинарных скобок. Обратите внимание, что оператор and имеет приоритет перед оператором or, то есть "&&" или "-a" будут оценены раньше, чем "||" или "-o".

Пятое отличие заключается в том, что синтаксис двойных скобок позволяет использовать оператор "=~" для сопоставления шаблонов. Более подробную информацию см. в таблице.

Синтаксис двойной парентезы

Существует также другой синтаксис для арифметических (основанных на числах) условий, скорее всего, заимствованный из оболочки Korn:

Приведенное выше условие истинно, если $num меньше или равно 5. Этот синтаксис может показаться программистам более привычным. Он содержит все "обычные" операторы, такие как "==", "<" и ">=". Он поддерживает комбинированные выражения "&&" и "||".

Погружение немного глубже

Основное правило bash, когда дело доходит до условий: 0 равно true, >0 равно false.

Это практически противоположно многим языкам программирования, где 0 равно false, а 1 (или больше) равно true. Причина этого в том, что оболочки, подобные bash, часто имеют дело с программами. Согласно конвенции UNIX, программы используют статус выхода для указания того, прошло ли выполнение нормально или произошла ошибка. Поскольку успешное выполнение не требует никаких объяснений, для него нужен только один статус выхода. Однако если возникла проблема, полезно знать, что именно пошло не так. Поэтому 0 используется для успешного выполнения, а 1-255 - для указания вида ошибки.

Значение чисел 1-255 отличается в зависимости от программы, возвращающей их.

В любом случае, if выполняет блок после then, когда команда возвращает 0. Да, условия - это команды. Фраза [ $foo -ge 3 ] возвращает статус выхода, и два других синтаксиса тоже! Поэтому есть изящный трюк, который можно использовать для быстрой проверки условия:

В этом примере "echo true" выполняется, только если "[ $foo -ge 3 ]" возвращает 0 (true). Почему так, спросите вы. Потому что bash оценивает условие только тогда, когда это необходимо. При использовании комбинированного выражения and оба условия должны быть истинными, чтобы комбинированное выражение вернуло true. Если первое условие возвращает false, не имеет значения, что возвращает второе; результат будет false.

Поэтому bash не оценивает второе условие, и это причина, по которой "echo true" не выполняется в примере. То же самое относится и к оператору or ("||"), где второе условие не оценивается, если первое истинно.

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