Тариф успешно добавлен в корзину
В корзину
url image

Условные операторы в bash. Часть 1

Выбор команд для выполнения в bash-скрипте можно контролировать с помощью особых блоков кода — управляющих конструкций. К ним относятся условные операторы, циклы и группирующие команды. 

В первой части материала об условных операторах расскажем, как работать с условными конструкциями для проверки истинности [ … ] и [[ … ]], во второй — об условных операторах if и case, а также о логических операторах && (логическое И) и || (логическое ИЛИ).

Одинарные [ … ] и двойные [[ … ]] квадратные скобки

Одинарные [ … ] и двойные [[ … ]] квадратные скобки — самостоятельные условные конструкции, которые проверяют истинность помещённого в них выражения. Также в них часто помещают тело условия после оператора if. От выбора конструкции зависит форма записи условия — оболочка интерпретирует выражения в одинарных квадратных скобках иначе, чем в двойных.

Конструкция [ … ] — встроенная команда (builtin) оболочки bash. Это форма записи команды test, которая проверяет выполнение условия. 

В этой конструкции для аргументов действуют подстановка значений переменных, разделение на слова и поиск по шаблонам (globbing — об этом подробно рассказано в статье Часть 2. Bash-скрипты. Переменные, комментарии, пользовательский ввод). Чтобы спецсимволы внутри одинарных квадратных скобок интерпретировались как операторы (например, =, >, &&, |, ., * и так далее), их нужно экранировать при помощи обратного слэша \ или двойных кавычек "". Внутри конструкции [ … ] нельзя работать с регулярными выражениями и сравнивать строки между собой.

Одинарные скобки используются не только в bash, но и в остальных POSIX-системах.

Пример использования:

file="file name"
[ -f "$file" ] && echo "$file — обычный файл"

Так как значение переменной file содержит пробел, внутри конструкции [ … ] имя переменной нужно заключить в кавычки, иначе оболочка интерпретирует значение переменной как два отдельных слова, и возникнет ошибка — указанный файл не будет найден.

Конструкция [[ … ]] — ключевое слово (keyword) оболочки bash. Помещаемые в неё аргументы интерпретируются особым образом — специальные символы не требуется экранировать, а разделение на слова и поиск по шаблонам не работают. Внутри двойных одинарных скобок можно работать с регулярными выражениями и сравнивать строки между собой.

Двойные квадратные скобки менее универсальны, чем одинарные — они предусмотрены в оболочках ksh, zsh и bash, но отсутствуют в sh, ash и dash.

Пример использования:

file="file name"
[[ -f $file ]] && echo "$file — обычный файл"

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

Выбор оператора сравнения зависит от договорённости в сообществе или предпочтений разработчика. Например, компания Google в своём стиле кода рекомендует использовать в shell-скриптах конструкцию [[ … ]] вместо [ … ], test и /usr/bin/[. По мнению авторов конвенции, это самый надёжный вариант записи: он позволяет избежать ошибок интерпретации, так как не требуется экранирование спецсимволов или иные способы записи операторов (например, -a вместо &&). Кроме того, внутри двойных квадратных скобок можно сравнивать последовательности символов и работать с регулярными выражениями, а конструкция [ … ] не поддерживает эти возможности.

Проверка файлов

В скриптах с оператором if часто проверяют тип и разрешения файлов. Для проверки используют оператор [ ... ] (команды test) и следующие его опции:

-f filename

возвращает true (устанавливает, что условие выполнено), если указанный файл существует и является обычным файлом (а не, например, каталогом или символической ссылкой)

-d filename

возвращает true, если указанный файл существует и является каталогом

-s filename

возвращает true, если указанный файл содержит данные (то есть размер файла больше нуля)

-r filename

возвращает true, если указанный файл доступен для чтения

-w filename

возвращает true, если указанный файл доступен для записи

-x filename

возвращает true, если указанный файл является исполняемым файлом

Пример проверки исполняемости файла:

#!/bin/bash 

if [ -x script.sh ]; then 
  echo 'script.sh можно запустить на исполнение'
else
  echo 'script.sh нельзя запустить на исполнение'
fi

Этот скрипт проверяет, может ли действующий пользователь запустить файл на исполнение — установлен ли для него бит исполнения x. Если этот бит присутствует, скрипт возвращает значение true, и выводится сообщение: script.sh можно запустить на исполнение. Если отсутствует — сообщение: script.sh нельзя запустить на исполнение.

Сравнение строк

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

string1 = string2 

string1 == string2

Возвращает true, если операнды (сущности, участвующие в операции) равны.

Особенности использования операторов = и == с операторами [ ... ] и [[ ... ]]

С одинарными квадратными скобками:

[ $a == R* ] — сравнение с шаблоном, содержащим подстановочные знаки; разбиение на слова

[ "$a" == "R*" ] — проверка на точное соответствие указанной в кавычках последовательности символов

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

[[ $a == R* ]] — сравнение с шаблоном, содержащим подстановочные знаки

[[ $a == "R*" ]] — проверка на точное соответствие указанной в кавычках последовательности символов

string1 != string2Возвращает true, если операнды не равны.
string1 > string2

Возвращает true, если правый операнд располагается первым при сортировке в алфавитном порядке:

bat > arc

string1 < string2

Возвращает true, если левый операнд располагается первым при сортировке в алфавитном порядке.

0a < 0c

-z stringВозвращает true, если длина строки равна нулю.
-n stringВозвращает true, если длина строки не равна нулю.
-v stringВозвращает true, если назначена переменная с таким именем.
"string" =~ regular_expression

Возвращает true, если строка соответствует регулярному выражению:

[[ $str =~ [0-9]+ ]] — проверка на наличие цифр в строке

Следующий скрипт проверяет, запущен ли определённый сервис, которым управляет systemctl — подсистема инициализации и управления службами во многих дистрибутивах Linux:

#!/bin/bash

echo "Введите название сервиса: "
read service_name
status=$(systemctl is-active $service_name)
if [ "$status" = "active" ]; then
  echo "Сервис $service_name запущен."
else
  echo "Сервис $service_name не запущен."
fi
  1. Пользователю предлагают ввести имя одного из системных сервисов Linux.
  2. Введённое значение подставляется в команду systemctl, которая проверяет состояние сервиса с указанным названием. Результат выполнения команды systemctl сохраняется в переменную status
  3. Если значение переменной — active, отображается сообщение о том, что сервис запущен. 
  4. Во всех прочих сценариях (включая случай, когда сервис не установлен в системе) отображается сообщение о том, что сервис не запущен.

Сравнение чисел

Для сравнения чисел используют  оператор [ ... ] и следующие операторы:

-eqравно (equal)
-neне равно (not equal)
-gtбольше (greater than)
-ltменьше (less than)
-geбольше или равно (greater or equal)
-le меньше или равно (less or equal)

Эти операторы работают только с целыми числами.

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

Команда установки пакета lm-sensors для операционных систем семейств Ubuntu и Debian:

sudo apt install lm-sensors

Для систем CentOS и RHEL: 

sudo yum install lm-sensors

Скрипт проверяет текущую температуру одного из ядер процессора — Core 0: 

#!/bin/bash

current_temp=$(sensors | grep "Core 0" | awk '{print $3}' | sed 's/+//; s/°C//' | head -n 1)
current_temp_int=$(bc <<< "${​current_temp}/1")
threshold=80
if [ "$current_temp_int" -gt "$threshold" ]; then
  echo "Внимание: высокая температура! Текущая температура: ${current_temp}°C."
else
  echo "Температура нормальная. Текущая температура: ${current_temp}°C."
fi

Скрипт выполняет следующие действия:

  1. В переменную current_temp записывается вывод конвейера из следующих команд:
    1. Вывод команды sensors передаётся команде grep для поиска строки (или строк) с фрагментом Core 0.
    2. Вывод grep передаётся команде для обработки текста awk, которая находит третье поле полученной строки и выводит его.
    3. Вывод awk передаётся команде sed, которая удаляет символ + перед значением температуры и °C после него.
    4. Так как процессоров с ядром Core 0 может быть несколько, утилита head оставляет только первую из обработанных строк с фрагментом Core 0.
  2. Так как операторы сравнения чисел работают только с целыми числами, а программа sensors выводит значения температуры с плавающей точкой, значение переменной current_temp преобразуется в целое: делится на единицу и передаётся в виде here-строки программе-калькулятору bc, а затем в преобразованном виде записывается в переменную current_temp_int.
  3. Переменной threshold присваивается значение 80.
  4. Команда echo выводит результат сравнения значений переменных current_temp_int и threshold.

Таким образом скрипт проверяет: значение переменной current_temp_int больше значения переменной threshold

  1. Если да, то выводится сообщение: 

    Внимание: повышенная температура! Текущая температура — <значение переменной $current_temp>.

  2. Если нет, то выводится сообщение: 

    Температура нормальная. Текущая температура — <значение переменной $current_temp>.

Блок-схема скрипта проверки температуры ядра процессора

Мы рассмотрели условные конструкции в языке bash: узнали, как работать с одинарными [ … ] и двойными [[ … ]] квадратными скобками, которые в bash-скриптах позволяют проверять выполнение условий для разных типов данных.

Во второй части статьи расскажем, как работать с операторами if и case, а также с логическими операторами && и ||.

Этот материал был полезен?

Скидка новым клиентам
Закажите сервер сегодня и получите скидку на первый месяц аренды!