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: Sleep із плаваючою комою на системах 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` вручну.

FAQ

Чи споживає `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` всередині скрипту `systemd` сервісного юніту `ExecStart`?

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

15%

Збережіть 15% на всі хостинг-послуги

Перевірте свої навички і отримайте Знижку на будь-який план хостингу

Використовуй код:

Skills
Почати