Перейти к основному содержимому

Ключевые слова и зарезервированные конструкции

Разработчику Архитектору

Ключевые слова и зарезервированные конструкции

Конструкции управления потоком выполнения

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

Условный оператор if

Конструкция if позволяет выполнять блок команд только в том случае, если заданное условие истинно. Синтаксис этого оператора требует наличия ключевого слова then после условия и fi для закрытия блока. Условием может служить результат выполнения любой команды, так как каждая команда возвращает код завершения: ноль означает успех (истина), любое другое число — ошибку (ложь).

if [ "$USER" = "root" ]; then
echo "Вы работаете под суперпользователем"
else
echo "Вы обычный пользователь"
fi

В данном примере проверяется имя текущего пользователя. Если переменная $USER содержит строку "root", выполняется первая ветка кода. В противном случае выполняется блок else. Завершающее слово fi является обязательным и закрывает весь условный оператор. Оно происходит от обратного написания слова "if".

Существует также конструкция elif, которая позволяет проверять дополнительные условия, если предыдущие не были выполнены. Это заменяет необходимость писать вложенные операторы if внутри блоков else.

if [ -f "/etc/passwd" ]; then
echo "Файл существует"
elif [ -d "/etc/passwd" ]; then
echo "Это директория"
else
echo "Путь не найден"
fi

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


Циклы повторения

Циклы позволяют выполнять один и тот же блок кода несколько раз. В Bash реализованы три основных типа циклов: for, while и until. Каждый из них имеет свою специфику применения и синтаксис.

Цикл for

Конструкция for предназначена для перебора элементов списка. Она идеально подходит для обработки массивов, аргументов командной строки или последовательности чисел.

for file in *.txt; do
echo "Обработка файла: $file"
done

Этот цикл проходит по всем файлам с расширением .txt в текущей директории. Переменная file принимает значение каждого файла по очереди, пока список не закончится. Завершающее слово done закрывает цикл.

Также можно использовать конструкцию for с диапазоном чисел, используя фигурные скобки.

for i in {1..5}; do
echo "Номер цикла: $i"
done

Это выведет числа от 1 до 5. Такой подход удобен, когда нужно выполнить действие определенное количество раз без необходимости создавать отдельный список.

Цикл while

Конструкция while выполняет блок команд столько раз, пока заданное условие остается истинным. Проверка условия происходит перед каждым выполнением тела цикла.

count=0
while [ $count -lt 5 ]; do
echo "Счетчик: $count"
count=$((count + 1))
done

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

Цикл while часто используется для чтения данных из потока ввода построчно.

while read line; do
echo "Получена строка: $line"
done < input.txt

Команда read считывает одну строку из файла input.txt. Пока команда успешно читает данные (возвращает код 0), цикл продолжается. Когда файл заканчивается, read возвращает код ошибки, и цикл завершается.

Цикл until

Конструкция until похожа на while, но работает наоборот: она выполняет тело цикла, пока условие ложно. Выполнение прекращается, когда условие становится истинным.

attempts=0
until [ $attempts -ge 3 ]; do
echo "Попытка номер: $((attempts + 1))"
attempts=$((attempts + 1))
done

Цикл будет выполняться три раза. На каждой итерации счетчик увеличивается, пока не достигнет значения 3. В этот момент условие станет истинным, и цикл завершится.


Команды управления циклами

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

Команда break немедленно прерывает выполнение текущего цикла. Управление передается команде, следующей за циклом. Можно указать числовой аргумент для выхода из нескольких вложенных циклов одновременно.

for i in {1..10}; do
if [ $i -eq 5 ]; then
break
fi
echo "Текущее значение: $i"
done

В этом примере цикл остановится сразу после достижения значения 5, не выводя это значение.

Команда continue пропускает оставшуюся часть тела текущей итерации цикла и переходит к проверке условия или следующему элементу списка.

for i in {1..5}; do
if [ $i -eq 3 ]; then
continue
fi
echo "Печатаем: $i"
done

При значении 3 вывод пропускается, и цикл сразу переходит к проверке следующего элемента.

Команда return завершает выполнение функции или скрипта и возвращает указанный код завершения. Если используется внутри функции, то управление возвращается вызвавшему коду.

check_value() {
local val=$1
if [ $val -lt 0 ]; then
return 1
fi
return 0
}

Если переданное значение отрицательное, функция возвращает код ошибки. Иначе возвращается код успеха.


Операторы сравнения и тестирования

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

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

Строковые операции позволяют проверять равенство, неравенство, пустоту и лексикографический порядок строк.

ОператорОписаниеПример
=Равенство строкif [ "$a" = "$b" ]
!=Неравенство строкif [ "$a" != "$b" ]
-zСтрока пустаif [ -z "$str" ]
-nСтрока не пустаif [ -n "$str" ]
<Лексикографически меньшеif [ "$a" \< "$b" ]
>Лексикографически большеif [ "$a" \> "$b" ]

Операторы < и > требуют экранирования символов \ или использования квадратных скобок [[ ]], так как они являются символами перенаправления вывода в оболочке.


Сравнение целых чисел

Арифметические операции в Bash выполняются через специальные операторы, отличные от символов математических действий.

ОператорОписаниеПример
-eqРавноif [ $a -eq $b ]
-neНе равноif [ $a -ne $b ]
-gtБольшеif [ $a -gt $b ]
-geБольше или равноif [ $a -ge $b ]
-ltМеньшеif [ $a -lt $b ]
-leМеньше или равноif [ $a -le $b ]

Эти операторы работают только с целыми числами. Попытка использовать их с дробными числами приведет к ошибке.


Сравнение файлов и директорий

Проверка состояния файлов является критически важной частью системного администрирования. Bash предоставляет множество флагов для проверки свойств файлов.

ФлагОписание
-eФайл или директория существуют
-fСуществует обычный файл
-dСуществует директория
-rФайл доступен для чтения
-wФайл доступен для записи
-xФайл доступен для исполнения
-sФайл не пустой (размер больше 0)
-OВладелец файла совпадает с текущим пользователем
-GГруппа файла совпадает с текущей группой
-ntЛевый файл новее правого
-otЛевый файл старее правого
-efФайлы имеют одинаковый inode

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

if [ -f "/etc/hosts" ] && [ -r "/etc/hosts" ]; then
echo "Файл доступен для чтения"
fi

Здесь проверяется существование файла и его права на чтение. Оператор && объединяет условия, требуя истинности обоих.


Логические операторы

Для объединения условий используются логические операторы && (и), || (или) и ! (не).

ОператорДействиеПриоритет
&&Возвращает истину, если оба операнда истинныВысокий
``
!Инвертирует значение условияВысокий
if [ -f "script.sh" ] && [ -x "script.sh" ]; then
./script.sh
fi

if [ ! -d "backup" ]; then
mkdir backup
fi

Первый пример запускает скрипт только если он существует и имеет права на исполнение. Второй пример создает директорию, если её нет.


Специальные конструкции и операторы

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

Оператор case

Конструкция case позволяет выбирать блок кода в зависимости от значения переменной. Она аналогична оператору switch в других языках программирования.

day=$(date +%A)
case $day in
Monday|Tuesday|Wednesday|Thursday|Friday)
echo "Рабочий день"
;;
Saturday|Sunday)
echo "Выходной"
;;
*)
echo "Неизвестный день"
;;
esac

Каждая ветка начинается с шаблона, за которым следует знак ). Блоки кода завершаются двумя точками с запятой ;;. Знак * в последней ветке служит универсальным шаблоном для всех остальных случаев.


Операторы перенаправления ввода и вывода

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

СимволОписание
>Перенаправление вывода в файл (замена)
>>Перенаправление вывода в файл (добавление)
<Перенаправление ввода из файла
2>Перенаправление вывода ошибок
&>Перенаправление всего вывода
``
<<Гербо-документ (ввод текста из скрипта)
<<<Гербо-строка (ввод строки)
echo "Привет" > output.txt
cat input.txt | grep "текст" >> result.txt

Гербо-документ позволяет передавать многострочный текст внутрь скрипта без создания временных файлов.

cat << EOF
Это строка 1
Это строка 2
Это строка 3
EOF

Арифметические выражения

Bash поддерживает выполнение арифметических операций двумя способами: через конструкцию $(( )) и через команду let.

sum=$(( a + b ))
difference=$(( a - b ))
product=$(( a * b ))
quotient=$(( a / b ))
remainder=$(( a % b ))
power=$(( a ** b ))
increment=$(( ++a ))
decrement=$(( --a ))

Также можно использовать команды let и (( )) для выполнения выражений.

let "sum = a + b"
(( sum = a + b ))

Внутри арифметических выражений можно использовать любые стандартные операторы C.


Расширения параметров

Расширения параметров позволяют манипулировать значениями переменных непосредственно в процессе их обращения.

РасширениеОписание
${var:-default}Использовать default, если var не определено или пусто
${var:=default}Присвоить default, если var не определено или пусто
${var:?message}Вывести message и завершить скрипт, если var не определено или пусто
${var:+replacement}Использовать replacement, если var определено и не пусто
${#var}Длина значения переменной
${var%pattern}Удалить минимальный суффикс, соответствующий паттерну
${var%%pattern}Удалить максимальный суффикс, соответствующий паттерну
${var#pattern}Удалить минимальный префикс, соответствующий паттерну
${var##pattern}Удалить максимальный префикс, соответствующий паттерну
name=""
echo "${name:-Гость}" # Выведет "Гость"

path="/home/user/docs/file.txt"
echo "${path%.txt}" # Выведет "/home/user/docs/file"
echo "${path##*/}" # Выведет "file.txt"

Эти расширения делают скрипты более гибкими и позволяют избегать множества проверок условий.


Обработка ошибок и управление состоянием

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

Код возврата и переменная $?

Каждая команда в Bash возвращает код завершения. Значение 0 означает успех, любое другое значение — ошибку. Последнее значение сохраняется в специальной переменной $?.

ls /nonexistent_directory
echo $? # Выведет 2

Проверка кода возврата позволяет принимать решения о дальнейших действиях.

if ! command_that_might_fail; then
echo "Команда вернула ошибку"
fi

Установка флагов поведения оболочки

Команда set позволяет изменить поведение самой оболочки.

ФлагОписание
set -eВыход из скрипта при первой ошибке
set -uВыход при обращении к неопределенной переменной
set -o pipefailВыход при ошибке в любом звене трубы
set -xВывод каждой команды перед выполнением (трассировка)
set -vВывод каждой команды после разбора (вербозность)
set -nТолько проверка синтаксиса без выполнения
#!/bin/bash
set -euo pipefail

# Скрипт автоматически завершится при любой ошибке
# или попытке обратиться к несуществующей переменной

Использование этих флагов в начале скрипта значительно повышает его надежность.


Ловушки сигналов trap

Конструкция trap позволяет перехватывать сигналы, отправляемые процессу, и выполнять определенные действия при их получении.

cleanup() {
echo "Очистка ресурсов..."
rm -f /tmp/temp_file_$$
exit 0
}

trap cleanup EXIT INT TERM HUP

Этот скрипт вызовет функцию cleanup при нормальном завершении (EXIT) или получении сигналов прерывания (INT, TERM, HUP). Это гарантирует очистку временных файлов даже при аварийном завершении.


Функции и локальные переменные

Функции в Bash позволяют инкапсулировать код и переиспользовать его.

calculate_sum() {
local a=$1
local b=$2
local result=$((a + b))
echo $result
return 0
}

sum=$(calculate_sum 5 7)
echo "Сумма: $sum"

Ключевое слово local объявляет переменную как локальную в рамках функции. Это предотвращает конфликты имен с глобальной областью видимости.


Работа с массивами и коллекциями данных

Bash поддерживает работу с массивами, начиная с версии 4.0. Массивы позволяют хранить списки значений и обращаться к ним по индексам.

fruits=("яблоко" "банан" "вишня")
echo ${fruits[0]} # Выведет "яблоко"
echo ${fruits[@]} # Выведет все элементы
echo ${#fruits[@]} # Выведет количество элементов

Можно добавлять элементы динамически.

fruits+=("груша")
fruits+=(["3"]="лимон")

Поддерживаются и ассоциативные массивы, где ключами служат строки.

declare -A colors
colors["red"]="#FF0000"
colors["green"]="#00FF00"
echo ${colors["red"]}

См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).