15%

Сэкономьте 15% на всех хостинговых услугах

Проверьте свои навыки и получите скидку на любой тарифный план

Используйте код:

Skills
Начать
08.10.2024

Использование команды `sleep` в Bash-скриптах на Linux

Команда `sleep` в Linux приостанавливает выполнение скрипта на точно заданный промежуток времени — указанный в секундах, минутах, часах или днях — с использованием синтаксиса `sleep [NUMBER][SUFFIX]`. Это один из наиболее критически важных примитивов в Bash-скриптинге, обеспечивающий ограничение частоты запросов, логику повторных попыток, синхронизацию процессов и автоматизацию по расписанию без использования внешних планировщиков.

В отличие от cron или `at`, `sleep` работает полностью в контексте собственного процесса скрипта, что делает его правильным инструментом, когда задержка должна быть относительной к завершению предыдущей команды, а не привязанной к абсолютному времени.

Синтаксис и справочник единиц времени

“`bash

sleep NUMBER[SUFFIX]

“`

СуффиксЕдиницаПримерЭквивалент в секундах
——–————————-———————–
`s`Секунды`sleep 30s`30
`m`Минуты`sleep 5m`300
`h`Часы`sleep 2h`7200
`d`Дни`sleep 1d`86400
(нет)Секунды`sleep 10`10

Суффикс является необязательным. Если он опущен, единицей по умолчанию являются секунды. В системах GNU/Linux (GNU coreutils) `sleep` также принимает значения с плавающей точкой и несколько аргументов — возможность, отсутствующая в реализациях BSD и macOS, если только GNU coreutils не установлен через Homebrew.

“`bash

GNU coreutils: both of these are valid

sleep 1.5

sleep 1m 30s # Equivalent to 90 seconds

“`

Важное замечание о переносимости: POSIX предписывает только целые секунды без суффикса. Если ваш скрипт должен работать на Alpine Linux (BusyBox), macOS или AIX, ограничьтесь `sleep INTEGER` и избегайте объединения нескольких аргументов.

Основные варианты использования в Bash-скриптах

1. Последовательная задержка между командами

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

“`bash

#!/bin/bash

echo "Restarting nginx…"

systemctl restart nginx

sleep 3

systemctl status nginx

“`

Пауза в 3 секунды здесь учитывает асинхронную последовательность запуска менеджера служб. Без неё `status` может сообщить устаревшее состояние, зафиксированное до полной инициализации процесса.

2. Цикл опроса с экспоненциальной выдержкой

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

“`bash

#!/bin/bash

MAX_RETRIES=6

DELAY=2

for (( attempt=1; attempt<=MAX_RETRIES; attempt++ )); do

if curl -sf https://api.example.com/health > /dev/null; then

echo "Service healthy on attempt $attempt."

exit 0

fi

echo "Attempt $attempt failed. Retrying in ${DELAY}s…"

sleep "$DELAY"

DELAY=$(( DELAY * 2 ))

done

echo "Service unreachable after $MAX_RETRIES attempts." >&2

exit 1

“`

При каждом сбое время ожидания удваивается: 2с, 4с, 8с, 16с, 32с, 64с. Максимальное суммарное время ожидания перед отказом составляет 126 секунд. Этот шаблон является стандартным в скриптах производственного развёртывания, проверках работоспособности и CI/CD-конвейерах.

3. API-вызовы с ограничением частоты запросов

При взаимодействии с API, применяющими квоты запросов, `sleep` обеспечивает соблюдение необходимого интервала между запросами:

“`bash

#!/bin/bash

API_KEY="your_key_here"

ENDPOINTS=("users" "orders" "products" "inventory")

for endpoint in "${ENDPOINTS[@]}"; do

curl -s -H "Authorization: Bearer $API_KEY"

"https://api.example.com/v1/${endpoint}"

-o "${endpoint}.json"

echo "Fetched: $endpoint"

sleep 1 # Respect 1 req/sec rate limit

done

“`

4. Выполнение фоновой задачи по таймеру

Запуск отложенной команды без блокировки текущего сеанса оболочки требует сочетания `sleep` с фоновым выполнением в подоболочке:

“`bash

Trigger a cache flush 60 seconds after deployment completes

( sleep 60 && redis-cli FLUSHDB ) &

echo "Cache flush scheduled. PID: $!"

“`

Переменная `$!` захватывает PID фоновой подоболочки, который впоследствии можно использовать с `wait` или `kill`, если задачу необходимо отменить.

5. Цикл сторожевого таймера и мониторинга процессов

“`bash

#!/bin/bash

SERVICE="mysqld"

CHECK_INTERVAL=30

while true; do

if ! pgrep -x "$SERVICE" > /dev/null; then

echo "$(date '+%Y-%m-%d %H:%M:%S') $SERVICE not running. Restarting…"

>> /var/log/watchdog.log

systemctl start "$SERVICE"

fi

sleep "$CHECK_INTERVAL"

done

“`

Этот шаблон используется в облегчённом надзоре за процессами, когда полноценный демон-супервизор (systemd, supervisord, s6) недоступен или неуместен — что характерно для контейнеризированных сред или минимальных экземпляров VPS Хостинга.

6. Таймер обратного отсчёта с обратной связью для пользователя

Для интерактивных скриптов, в которых оператору необходима информация об оставшемся времени ожидания:

“`bash

#!/bin/bash

COUNTDOWN=10

echo "Starting in:"

for (( i=COUNTDOWN; i>=1; i– )); do

printf "r%2d seconds remaining…" "$i"

sleep 1

done

printf "rGo! n"

“`

`printf "r"` перезаписывает текущую строку вместо добавления новых строк, обеспечивая чистый терминальный обратный отсчёт.

`sleep` в сравнении с альтернативными механизмами синхронизации

МеханизмГранулярностьБлокирует оболочкуАбсолютное времяВариант использования
—————–—————–————–————————————————————–
`sleep`Субсекундная (GNU)Да (если не `&`)НетОтносительные задержки внутри скриптов
`cron`1 минутаНетДаПовторяющиеся запланированные задания
`at`1 минутаНетДаОднократное выполнение в будущем
`systemd timer`1 секундаНетДаПостоянные, журналируемые задания с учётом зависимостей
`usleep` (C)МикросекундаДаНетТочность на уровне ядра/C (не является нативным для Bash)
`read -t`СубсекунднаяДаНетТайм-аут с возможным вводом от пользователя

Когда использовать `read -t` вместо `sleep`: Если скрипту необходимо приостановиться, но при этом позволить пользователю прервать выполнение или ответить во время ожидания, `read -t SECONDS` является правильным примитивом. Он возвращает код выхода 1 при тайм-ауте и 0, если пользователь нажимает Enter, предоставляя условную логику без отдельного процесса.

“`bash

echo "Press Enter to skip the 10-second wait, or wait for automatic continuation."

read -t 10 -r || true

echo "Continuing…"

“`

Точность, числа с плавающей точкой и поведение на разных платформах

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

“`bash

Tail a log file and print one line per 0.2 seconds (5 lines/sec)

while IFS= read -r line; do

echo "$line"

sleep 0.2

done < /var/log/app.log

“`

Фактическая продолжительность сна является минимальной, а не гарантированной. Планировщик ядра может разбудить процесс немного позже в зависимости от нагрузки на систему и разрешения таймера (`CONFIG_HZ`). На сильно загруженном Выделенном сервере, выполняющем десятки параллельных процессов, `sleep 0.1` может фактически приостановиться на 0,11–0,15 секунды. Для скриптов, в которых такое смещение недопустимо, используйте ссылку на монотонные часы:

“`bash

#!/bin/bash

INTERVAL=5

NEXT=$(date +%s%N) # Current time in nanoseconds

while true; do

NEXT=$(( NEXT + INTERVAL * 1000000000 ))

do_work

NOW=$(date +%s%N)

REMAINING=$(( (NEXT – NOW) / 1000000 )) # Convert to milliseconds

[ "$REMAINING" -gt 0 ] && sleep "$(echo "scale=3; $REMAINING/1000" | bc)"

done

“`

Этот цикл с компенсацией смещения поддерживает постоянный интервал независимо от того, сколько времени занимает `do_work`.

Обработка сигналов и прерывание `sleep`

Выполняющийся процесс `sleep` реагирует на сигналы. Отправка `SIGALRM` процессу sleep немедленно его пробуждает. На практике нажатие `Ctrl+C` отправляет `SIGINT` всей группе процессов, завершая как скрипт, так и любой активный `sleep`.

Чтобы скрипт корректно обрабатывал прерывание во время сна:

“`bash

#!/bin/bash

cleanup() {

echo "Interrupted. Cleaning up…"

exit 1

}

trap cleanup SIGINT SIGTERM

echo "Waiting 60 seconds…"

sleep 60 &

SLEEP_PID=$!

wait "$SLEEP_PID"

echo "Wait complete."

“`

Переводя `sleep` в фоновый режим и используя `wait`, `trap` срабатывает немедленно при получении `SIGINT`, а не откладывается до завершения сна. Это правильный шаблон для долго выполняющихся скриптов автоматизации на производственных серверах.

Практические подводные камни и граничные случаи

Подводный камень 1: Использование `sleep` в плотных циклах без условия завершения. Цикл `while true; do sleep 1; done` без пути выхода будет выполняться бесконечно, занимая слот процесса и накапливаясь в выводе `ps`. Всегда определяйте максимальное количество итераций или сторожевое условие.

Подводный камень 2: Предположение о синхронности `sleep` с подоболочками. При разветвлении подоболочки с помощью `&` родительский скрипт не ожидает завершения `sleep` подоболочки, если явно не вызван `wait`. Это приводит к состояниям гонки в скриптах параллельного развёртывания.

Подводный камень 3: Жёсткое кодирование задержек для готовности службы. Использование `sleep 5` после запуска службы ненадёжно. Служба может быть готова через 1 секунду или может занять 30 секунд под нагрузкой. Надёжной альтернативой является опрос готовности:

“`bash

#!/bin/bash

wait_for_port() {

local host="$1" port="$2" timeout="${3:-30}"

local elapsed=0

until nc -z "$host" "$port" 2>/dev/null; do

[ "$elapsed" -ge "$timeout" ] && return 1

sleep 1

(( elapsed++ ))

done

}

systemctl start postgresql

wait_for_port localhost 5432 30 && echo "PostgreSQL ready."

“`

Подводный камень 4: Сон с плавающей точкой в системах BusyBox. Контейнеры Alpine Linux используют `sleep` из BusyBox, который не поддерживает десятичные значения. Попытка выполнить `sleep 0.5` вызовет ошибку. Проверяйте своё окружение перед развёртыванием скриптов, использующих субсекундную точность.

Интеграция `sleep` в автоматизированные серверные рабочие процессы

На управляемом VPS с cPanel скрипты автоматизированного обслуживания часто сочетают `sleep` с cron для реализации субминутного планирования. Поскольку минимальное разрешение cron составляет одну минуту, можно добиться 15-секундных интервалов следующим образом:

“`bash

crontab entry — runs the script 4 times per minute

  • * * * * /usr/local/bin/check_queue.sh
  • * * * * sleep 15 && /usr/local/bin/check_queue.sh
  • * * * * sleep 30 && /usr/local/bin/check_queue.sh
  • * * * * sleep 45 && /usr/local/bin/check_queue.sh

“`

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

В скриптах обновления SSL-сертификатов `sleep` обеспечивает задержку между попытками, когда для распространения ACME-запроса требуется истечение DNS TTL до того, как CA сможет подтвердить право собственности. Если вы управляете сертификатами на собственной инфраструктуре, SSL-сертификаты с автоматизированными конвейерами обновления выигрывают от точно настроенных интервалов повторных попыток.

Аналогично, скрипты проверки распространения домена — полезные после обновления записей через Регистрацию доменов — используют циклы `sleep` для опроса DNS-резолверов с интервалами, соответствующими ожидаемым значениям TTL.

Матрица решений: выбор правильной стратегии задержки

СценарийРекомендуемый подход
———————————————–—————————————————
Фиксированная пауза между двумя последовательными командами`sleep N`
Повторные попытки до успеха, предотвращение эффекта «стада»Экспоненциальная выдержка с `sleep`
Повторяющаяся задача каждые N минут`cron` (не `sleep`)
Субминутная повторяющаяся задача`cron` + трюк со смещением `sleep`
Задержка без блокировки терминала`( sleep N && command ) &`
Пауза с возможностью прерывания пользователем`sleep N &` + `wait $!` + `trap`
Проверка готовности службыЦикл опроса порта/работоспособности с `sleep 1` на попытку
Высокоточный интервал (с компенсацией смещения)Ссылка на монотонные часы с вычисленным `sleep`
Субсекундная задержка на Alpine/BusyBoxИзбегайте; используйте целые секунды или смените базовый образ

Ключевые технические выводы

  • Всегда используйте `sleep "$VARIABLE"` с двойными кавычками, чтобы предотвратить ошибки разбиения слов, когда переменная содержит десятичное значение.
  • Предпочитайте `sleep 1m 30s` вместо `sleep 90` для удобочитаемости в долго выполняющихся скриптах обслуживания.
  • Переводите `sleep` в фоновый режим с помощью `wait` и `trap` всякий раз, когда скрипт должен реагировать на сигналы во время паузы.
  • Никогда не используйте жёстко закодированный `sleep` как замену надлежащей проверки готовности — используйте цикл опроса с тайм-аутом.
  • Проверяйте поведение `sleep` на целевой ОС перед развёртыванием скриптов, использующих числа с плавающей точкой или синтаксис с несколькими аргументами.
  • На производственных серверах записывайте временну́ю метку до и после длительных вызовов `sleep` для обнаружения смещения планировщика при анализе инцидентов.
  • При создании автоматизации на Панелях управления VPS убедитесь, что планировщик задач панели уже обеспечивает управление интервалами, прежде чем добавлять логику `sleep` вручную.

Часто задаваемые вопросы

Потребляет ли `sleep` CPU во время ожидания?

Нет. `sleep` вызывает `nanosleep()` (или эквивалент) на уровне ядра, переводя процесс в состояние прерываемого сна (`S` в выводе `ps`). Во время ожидания он не потребляет циклов CPU — только небольшой объём памяти для записи процесса в таблице процессов.

Каково максимальное значение, принимаемое `sleep`?

В GNU/Linux `sleep` принимает значения до пределов числа с плавающей точкой `double`, что практически не ограничено для реальных задач. `sleep 1d` (86400 секунд) является распространённым значением; `sleep 365d` допустимо. Практическим ограничением является время работы системы.

Почему `sleep 0.5` не работает в моём Docker-контейнере?

Alpine Linux использует BusyBox, реализация `sleep` которого принимает только целые секунды. Перейдите на базовый образ Debian или Ubuntu либо установите GNU coreutils (`apk add coreutils`), чтобы включить поддержку десятичных значений.

Можно ли отменить фоновый процесс `sleep`?

Да. Захватите его PID с помощью `SLEEP_PID=$!` сразу после перевода в фоновый режим, затем используйте `kill "$SLEEP_PID"` для его завершения. Если вы использовали `( sleep N && command ) &`, завершение PID подоболочки также предотвратит выполнение последующей команды.

Безопасно ли использовать `sleep` внутри скрипта `ExecStart` юнита `systemd`?

Да, но с оговорками. Если юнит службы имеет установленный `TimeoutStartSec`, длительный `sleep` во время запуска приведёт к тому, что systemd завершит службу как неудачный запуск. Для задержек после запуска используйте `ExecStartPost` с опросом готовности или настройте `Type=forking` с надлежащим управлением PID-файлом, а не полагайтесь на `sleep` для отсрочки инициализации.

15%

Сэкономьте 15% на всех хостинговых услугах

Проверьте свои навыки и получите скидку на любой тарифный план

Используйте код:

Skills
Начать