Циклы позволяют автоматизировать выполнение однотипных действий в программах. Цикл while - один из базовых и полезных циклов в скриптинге Bash. Давайте разберемся с его работой.
Общие сведения о циклах while в Bash
Цикл while выполняет блок кода, пока заданное условие истинно. Синтаксис:
while [condition] do # блок кода done
Пока условие истинно, блок кода выполняется снова и снова. Часто цикл while используется для обработки файлов построчно или элементов массива.
Бесконечные циклы while true
Цикл while можно сделать бесконечным, указав условие while true
. Такой цикл никогда не завершится сам по себе. Чтобы выйти из него, нужно использовать оператор break
или выполнить exit
.
Бесконечные циклы полезны для непрерывного мониторинга системы. Например, следить за ростом лог-файла:
while true do current_size=$(wc -c /var/log/syslog) sleep 5 done
Чтение и обработка файлов
Цикл while часто используется для построчной обработки текстовых файлов:
while read line do echo $line done < файл.txt
Файл подается на вход цикла через перенаправление < файл.txt
. Команда read
считывает строки по одной.
Операторы управления циклом
Для управления выполнением цикла while используются операторы break
и continue
:
break
- досрочный выход из циклаcontinue
- пропуск текущей итерации цикла
Простые примеры циклов while
Цикл с переменной-счетчиком
Классический цикл с счетчиком от 0 до 4:
i=0 while [ $i -lt 5 ]; do echo $i i=$((i+1)) done
На каждой итерации счетчик i
увеличивается на 1. Цикл выполняется, пока i
меньше 5.
Цикл с прерыванием по условию (break)
i=0 while true; do echo $i if [ $i -eq 2 ]; then break fi i=$((i+1)) done
Как только переменная i
равна 2, оператор break
прервет цикл.
Бесконечный цикл с выходом по команде
while true do read -p "Введите Q для выхода: " var if [ "$var" == "Q" ] ; then echo "Выход" break fi # действия цикла done
Цикл бесконечный, но можно выйти из него, введя Q
в запросе. Используется для интерактивных скриптов.
Цикл while для чтения аргументов командной строки
Цикл while удобен для разбора аргументов скрипта:
while [[ $# -gt 0 ]]; do case $1 in -a|--all) all="true";; -f|--file) file="$2"; shift;; *) echo "Неизвестный параметр $1"; exit 1;; esac shift done
Переменная $#
хранит количество аргументов. Цикл работает, пока аргументы есть. Оператор shift
сдвигает параметры на 1.
Обработка аргументов через $1, $2 и т.д.
Доступ к конкретным аргументам осуществляется через $1
, $2
и т.д:
while [ -n "$1" ] do case "$1" in -a) echo "Найден параметр -a";; -b) arg="$2"; echo "Аргумент -b: $arg"; shift;; *) echo "Неизвестный параметр $1"; exit 1;; esac shift done
Тут $1
- текущий рассматриваемый параметр, $2
- следующий за ним.
Проверка обязательных параметров
Можно проверить, что нужные параметры переданы:
while [[ $# -gt 0 ]]; do # разбор параметров done if [ -z "$file" ]; then echo "Не указан обязательный параметр --file" exit 1 fi
Если переменная $file
пустая после цикла - значит параметр не задан.
Чтение данных из файла построчно
while read line; do echo "$line" done < файл.txt
Команда read
в цикле читает файл построчно. Файл подается через перенаправление < файл.txt
.
Обработка разделителей строк
Чтобы read
не интерпретировал символы \\
нужно:
while IFS= read -r line; do # обработка done < файл.txt
Параметр IFS=
отключает разделители. Флаг -r
не интерпретирует экранирование.
Чтение по символам/блокам
Опции -n
и -t
позволяют читать:
-n 5
- по 5 символов-t 2
- таймаут в 2 секунды
Работа с потоками
Данные в цикл можно подавать не только из файла, но и из стандартных потоков:
# stdin while read line; do echo $line done # stdout while read line; do echo $line done < <(ls -l)
Таким образом реализуется обработка ввода/вывода в скрипте.
Мониторинг процессов и системы
Циклы while позволяют организовать мониторинг и ожидание событий в системе.
Отслеживание изменения размера файла
last_size=0 while true; do current_size=$(wc -c файл.txt) if [ $current_size -ne $last_size ]; then echo "Размер изменился на: $((current_size - last_size))" fi last_size=$current_size sleep 2 done
Скрипт каждые 2 секунды проверяет размер файла и выводит изменение.
Ожидание события
while [ ! -d /tmp/new_dir ]; do echo "Ждем появления директории /tmp/new_dir" sleep 5 done echo "Директория появилась"
Цикл работает, пока директория не появится. Полезно при ожидании событий.
Получение вывода команды
out=$(mkfifo /tmp/pipe) ssh server $(cat /tmp/pipe) & while read line; do echo "$line" done < /tmp/pipe rm /tmp/pipe
Запускаем удаленную команду через SSH и читаем ее вывод через именованный канал.
Работа с массивами и словарями
Циклы while используются для итерации по элементам коллекций данных.
Цикл по массиву
arr=(1 2 3 4) i=0 while [ $i -lt ${#arr[@]} ]; do echo ${arr[$i]} i=$((i+1)) done
Переменная ${#arr[@]}
содержит размер массива arr
.
Обход ключей словаря
declare -A dict=( [a]=1 [b]=2 ) for key in "${!dict[@]}"; do echo "$key: ${dict[$key]}" done
Оператор "${!dict[@]}"
возвращает все ключи словаря dict
.
Добавление элементов
sites=([google]=1 [ya]=2) while read site; do sites[$site]=0 done < файл со списком сайтов
Цикл добавляет ключи из файла со списком сайтов в словарь.
Удаление элементов
sites=([google]=1 [ya]=2 [bing]=3) while read key; do unset sites[$key] done < файл со списком ключей для удаления
Цикл удаляет ключи, перечисленные в файле со списком ключей, из словаря.
Дополнительные возможности цикла while
Рассмотрим некоторые расширенные возможности цикла while в Bash.
Обработка ошибок
Чтобы перехватывать ошибки внутри цикла, используется конструкция:
while true; do command status=$? if [ $status -ne 0 ]; then echo "Произошла ошибка" >&2 break fi done
Переменная $?
хранит код возврата последней команды. При ошибке можно выйти из цикла.
Задержка выполнения
Чтобы добавить паузу между итерациями цикла, используется sleep
:
while true; do # код цикла sleep 5 done
Пауза в 5 секунд будет после каждой итерации.
Обработка сигналов
trap 'exit 0' SIGINT SIGTERM while true; do # код цикла done
Конструкция trap
перехватывает сигналы SIGINT
и SIGTERM
, чтобы цикл корректно завершился.
Рекурсивные циклы
#!/bin/bash function loop { while true; do # код цикла loop done } loop
Функция loop
рекурсивно вызывает сама себя, создавая бесконечный цикл.
Примеры практического применения
Пакетная обработка файлов
while read file; do convert "$file" "${file%.jpg}.png" done < files.txt
Цикл конвертирует изображения из списка в файле files.txt
из jpg в png.
Мониторинг процесса
while true; do if ! ps aux | grep "[p]rocess"; then echo "Процесс остановлен" break fi sleep 5 done
Цикл следит за запущенным процессом и выводит уведомление, когда процесс завершится.
Построчная запись в файл
while read line; do echo "$line" >> file.txt done < lines.txt
Скрипт записывает строки из lines.txt
в конец file.txt
построчно.
Цикл while выполняет блок кода, пока заданное условие истинно. Синтаксис:
while [condition] do # блок кода done
Пока условие истинно, блок кода выполняется снова и снова. Часто цикл while используется для обработки файлов построчно или элементов массива.
Бесконечные циклы while true
Цикл while можно сделать бесконечным, указав условие while true
. Такой цикл никогда не завершится сам по себе. Чтобы выйти из него, нужно использовать оператор break
или выполнить exit
.
Бесконечные циклы полезны для непрерывного мониторинга системы. Например, следить за ростом лог-файла:
while true do current_size=$(wc -c /var/log/syslog) sleep 5 done
Чтение и обработка файлов
Цикл while часто используется для построчной обработки текстовых файлов:
while read line do echo $line done < файл.txt
Файл подается на вход цикла через перенаправление < файл.txt
. Команда read
считывает строки по одной.
Операторы управления циклом
Для управления выполнением цикла while используются операторы break
и continue
:
-
break
- досрочный выход из цикла -
continue
- пропуск текущей итерации цикла
Простые примеры циклов while
Цикл с переменной-счетчиком
Классический цикл с счетчиком от 0 до 4:
i=0 while [ $i -lt 5 ]; do echo $i i=$((i+1)) done
На каждой итерации счетчик i
увеличивается на 1. Цикл выполняется, пока i
меньше 5.
Бесконечный цикл с выходом по команде
while true do read -p "Введите Q для выхода: " var if [ "$var" == "Q" ] ; then echo "Выход" break fi # действия цикла done
Цикл бесконечный, но можно выйти из него, введя Q
в запросе. Используется для интерактивных скриптов.
Цикл while для чтения аргументов командной строки
Цикл while удобен для разбора аргументов скрипта:
while [[ $# -gt 0 ]]; do case $1 in -a|--all) all="true";; -f|--file) file="$2"; shift;; *) echo "Неизвестный параметр $1"; exit 1;; esac shift done
Переменная $#
хранит количество аргументов. Цикл работает, пока аргументы есть. Оператор shift
сдвигает параметры на 1.
Обработка аргументов через $1, $2 и т.д.
Доступ к конкретным аргументам осуществляется через $1
, $2
и т.д:
while [ -n "$1" ] do case "$1" in -a) echo "Найден параметр -a";; -b) arg="$2"; echo "Аргумент -b: $arg"; shift;; *) echo "Неизвестный параметр $1"; exit 1;; esac shift done
Тут $1
- текущий рассматриваемый параметр, $2
- следующий за ним.
Проверка обязательных параметров
Можно проверить, что нужные параметры переданы:
while [[ $# -gt 0 ]]; do # разбор параметров done if [ -z "$file" ]; then echo "Не указан обязательный параметр --file" exit 1 fi
Если переменная $file
пустая после цикла - значит параметр не задан.
Чтение данных из файла построчно
while read line; do echo "$line" done < файл.txt
Команда read
в цикле читает файл построчно. Файл подается через перенаправление < файл.txt
.
Обработка разделителей строк
Чтобы read
не интерпретировал символы \\
нужно:
while IFS= read -r line; do # обработка done < файл.txt
Параметр IFS=
отключает разделители. Флаг -r
не интерпретирует экранирование.
Чтение по символам/блокам
Опции -n
и -t
позволяют читать:
-
-n 5
- по 5 символов -
-t 2
- таймаут в 2 секунды
Работа с потоками
Данные в цикл можно подавать не только из файла, но и из стандартных потоков:
# stdin while read line; do echo $line done # stdout while read line; do echo $line done < <(ls -l)
Таким образом реализуется обработка ввода/вывода в скрипте.