15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij
08.10.2024

Używanie polecenia `sleep` w skryptach Bash na Linux

Polecenie `sleep` w Linux wstrzymuje wykonywanie skryptu na precyzyjnie określony czas — podany w sekundach, minutach, godzinach lub dniach — przy użyciu składni `sleep [NUMBER][SUFFIX]`. Jest to jedno z najbardziej krytycznych operacyjnie prymitywów w skryptach Bash, umożliwiające ograniczanie częstotliwości żądań, logikę ponownych prób, synchronizację procesów i automatyzację czasową bez konieczności korzystania z zewnętrznych harmonogramów.

W przeciwieństwie do cron lub `at`, `sleep` działa całkowicie w kontekście procesu własnego skryptu, co czyni go właściwym narzędziem, gdy opóźnienie musi być względne wobec zakończenia poprzedniego polecenia, a nie bezwzględnego czasu zegarowego.

Składnia i odniesienie do jednostek czasu

“`bash

sleep NUMBER[SUFFIX]

“`

SufiksJednostkaPrzykładOdpowiednik w sekundach
——–————————-———————–
`s`Sekundy`sleep 30s`30
`m`Minuty`sleep 5m`300
`h`Godziny`sleep 2h`7200
`d`Dni`sleep 1d`86400
(brak)Sekundy`sleep 10`10

Sufiks jest opcjonalny. Gdy zostanie pominięty, jednostka domyślnie przyjmuje wartość sekund. W systemach GNU/Linux (GNU coreutils), `sleep` akceptuje również wartości zmiennoprzecinkowe i wiele argumentów — funkcja niedostępna w implementacjach BSD i macOS, chyba że GNU coreutils jest zainstalowane przez Homebrew.

“`bash

GNU coreutils: both of these are valid

sleep 1.5

sleep 1m 30s # Equivalent to 90 seconds

“`

Krytyczna uwaga dotycząca przenośności: POSIX wymaga jedynie całkowitoliczbowych sekund bez sufiksu. Jeśli skrypt musi działać na Alpine Linux (BusyBox), macOS lub AIX, ogranicz się do `sleep INTEGER` i unikaj łączenia wielu argumentów.

Podstawowe przypadki użycia w skryptach Bash

1. Sekwencyjne opóźnienie między poleceniami

Najprostsze zastosowanie — wstawianie pauzy między dwiema operacjami, gdy drugie polecenie nie może się rozpocząć, dopóki warunek rzeczywisty nie zdąży się ustabilizować:

“`bash

#!/bin/bash

echo "Restarting nginx…"

systemctl restart nginx

sleep 3

systemctl status nginx

“`

Pauza 3-sekundowa uwzględnia tutaj asynchroniczną sekwencję uruchamiania menedżera usług. Bez niej `status` może zgłosić nieaktualny stan przechwycony przed pełną inicjalizacją procesu.

2. Pętla odpytywania z wykładniczym wycofaniem

Naiwna pętla ponownych prób ze stałym interwałem marnuje zasoby i może zwiększać obciążenie przeciążonej usługi downstream. Właściwym wzorcem jest wykładnicze wycofanie z jitterem:

“`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

“`

Czas oczekiwania podwaja się przy każdym niepowodzeniu: 2s, 4s, 8s, 16s, 32s, 64s. Całkowity maksymalny czas oczekiwania przed rezygnacją wynosi 126 sekund. Ten wzorzec jest standardem w skryptach wdrożeń produkcyjnych, kontrolach stanu i potokach CI/CD.

3. Wywołania API z ograniczeniem częstotliwości

Podczas interakcji z API wymuszającymi limity żądań, `sleep` egzekwuje wymagany interwał między żądaniami:

“`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. Wykonywanie zadań w tle z opóźnieniem czasowym

Uruchomienie opóźnionego polecenia bez blokowania bieżącej sesji powłoki wymaga połączenia `sleep` z uruchamianiem podpowłoki w tle:

“`bash

Trigger a cache flush 60 seconds after deployment completes

( sleep 60 && redis-cli FLUSHDB ) &

echo "Cache flush scheduled. PID: $!"

“`

Zmienna `$!` przechwytuje PID podpowłoki działającej w tle, który można później użyć z `wait` lub `kill`, jeśli zadanie wymaga anulowania.

5. Pętla watchdog i monitora procesów

“`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

“`

Ten wzorzec jest używany w lekkim nadzorze procesów, gdy pełny demon nadzorcy (systemd, supervisord, s6) jest niedostępny lub nieodpowiedni — powszechne w środowiskach kontenerowych lub minimalnych instancjach VPS Hosting.

6. Odliczanie z informacją zwrotną dla użytkownika

W przypadku skryptów interaktywnych, gdzie operator potrzebuje wglądu w pozostały czas oczekiwania:

“`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"` nadpisuje bieżącą linię zamiast dołączać nowe linie, tworząc czyste odliczanie w terminalu.

`sleep` a alternatywne mechanizmy czasowe

MechanizmGranularnośćBlokuje powłokęCzas bezwzględnyPrzypadek użycia
—————–—————–————–————————————————————–
`sleep`Poniżej sekundy (GNU)Tak (chyba że `&`)NieWzględne opóźnienia w skryptach
`cron`1 minutaNieTakCykliczne zaplanowane zadania
`at`1 minutaNieTakJednorazowe przyszłe wykonanie
`systemd timer`1 sekundaNieTakTrwałe, rejestrowane zadania z obsługą zależności
`usleep` (C)MikrosekundaTakNiePrecyzja na poziomie jądra/C (nie natywna dla Bash)
`read -t`Poniżej sekundyTakNieLimit czasu z opcjonalnym wejściem użytkownika

Kiedy używać `read -t` zamiast `sleep`: Jeśli skrypt musi się zatrzymać, ale jednocześnie umożliwić użytkownikowi przerwanie lub odpowiedź podczas oczekiwania, `read -t SECONDS` jest właściwym prymitywem. Zwraca kod wyjścia 1 po upływie limitu czasu i 0, gdy użytkownik naciśnie Enter, dając logikę warunkową bez osobnego procesu.

“`bash

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

read -t 10 -r || true

echo "Continuing…"

“`

Precyzja, wartości zmiennoprzecinkowe i zachowanie na różnych platformach

GNU `sleep` akceptuje ułamki dziesiętne, co ma znaczenie w skryptach sterujących animacjami, ograniczających śledzenie logów lub symulujących kanały danych w czasie rzeczywistym:

“`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

“`

Rzeczywisty czas uśpienia jest wartością minimalną, nie gwarancją. Harmonogram jądra może obudzić proces nieco później w zależności od obciążenia systemu i rozdzielczości timera (`CONFIG_HZ`). Na mocno obciążonym Serwerze Dedykowanym obsługującym dziesiątki równoległych procesów, `sleep 0.1` może faktycznie wstrzymać działanie na 0,11–0,15 sekundy. W przypadku skryptów, gdzie taki dryft jest niedopuszczalny, należy użyć odwołania do zegara monotonicznego:

“`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

“`

Ta pętla kompensująca dryft utrzymuje stały interwał niezależnie od tego, jak długo trwa `do_work`.

Obsługa sygnałów i przerywanie `sleep`

Działający proces `sleep` reaguje na sygnały. Wysłanie `SIGALRM` do procesu sleep natychmiast go budzi. Bardziej praktycznie, naciśnięcie `Ctrl+C` wysyła `SIGINT` do całej grupy procesów, kończąc zarówno skrypt, jak i każdy działający na pierwszym planie `sleep`.

Aby skrypt czysto obsługiwał przerwanie podczas uśpienia:

“`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."

“`

Poprzez uruchomienie `sleep` w tle i użycie `wait`, `trap` uruchamia się natychmiast po `SIGINT`, zamiast być odroczonym do zakończenia uśpienia. Jest to właściwy wzorzec dla długo działających skryptów automatyzacji na serwerach produkcyjnych.

Praktyczne pułapki i przypadki brzegowe

Pułapka 1: Używanie `sleep` w ciasnych pętlach bez warunku zakończenia. Pętla `while true; do sleep 1; done` bez ścieżki wyjścia będzie działać w nieskończoność, zajmując slot procesu i kumulując się w wynikach `ps`. Zawsze definiuj maksymalną liczbę iteracji lub warunek sentinel.

Pułapka 2: Zakładanie, że `sleep` jest synchroniczne z podpowłokami. Gdy rozgałęziasz podpowłokę za pomocą `&`, skrypt nadrzędny nie czeka na zakończenie `sleep` podpowłoki, chyba że jawnie wywołasz `wait`. Powoduje to wyścigi w równoległych skryptach wdrożeniowych.

Pułapka 3: Hardkodowanie opóźnień dla gotowości usługi. Używanie `sleep 5` po uruchomieniu usługi jest zawodne. Usługa może być gotowa w 1 sekundę lub może potrzebować 30 sekund pod obciążeniem. Solidną alternatywą jest odpytywanie gotowości:

“`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."

“`

Pułapka 4: Zmiennoprzecinkowe uśpienie w systemach BusyBox. Kontenery Alpine Linux używają implementacji `sleep` BusyBox, która nie obsługuje wartości dziesiętnych. Próba użycia `sleep 0.5` spowoduje błąd. Sprawdź swoje środowisko przed wdrożeniem skryptów korzystających z precyzji poniżej sekundy.

Integracja `sleep` w zautomatyzowanych przepływach pracy serwera

Na zarządzanym VPS z cPanel, zautomatyzowane skrypty konserwacyjne często łączą `sleep` z cron w celu implementacji harmonogramowania poniżej minuty. Ponieważ minimalna rozdzielczość cron wynosi jedną minutę, można osiągnąć interwały 15-sekundowe w następujący sposób:

“`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

“`

Technika ta jest powszechnie stosowana w procesorach kolejek, kontrolach stanu i zbieraczach metryk na współdzielonej infrastrukturze, gdzie instalacja dedykowanego harmonogramu zadań nie jest dozwolona.

W skryptach odnawiania certyfikatów SSL, `sleep` zapewnia opóźnienie między próbami, gdy propagacja wyzwania ACME wymaga wygaśnięcia DNS TTL przed weryfikacją własności przez CA. Jeśli zarządzasz certyfikatami na własnej infrastrukturze, Certyfikaty SSL z automatycznymi potokami odnawiania korzystają z precyzyjnie dostrojonych interwałów ponownych prób.

Podobnie, skrypty weryfikacji propagacji domeny — przydatne po aktualizacji rekordów przez Rejestrację Domen — używają pętli `sleep` do odpytywania resolverów DNS w interwałach dostosowanych do oczekiwanych wartości TTL.

Macierz decyzyjna: wybór właściwej strategii opóźnienia

ScenariuszZalecane podejście
———————————————–—————————————————
Stała pauza między dwoma sekwencyjnymi poleceniami`sleep N`
Ponowne próby do sukcesu, unikanie efektu thundering herdWykładnicze wycofanie z `sleep`
Cykliczne zadanie co N minut`cron` (nie `sleep`)
Cykliczne zadanie poniżej minuty`cron` + przesunięcie `sleep`
Opóźnienie bez blokowania terminala`( sleep N && command ) &`
Pauza z możliwością przerwania przez użytkownika`sleep N &` + `wait $!` + `trap`
Sprawdzanie gotowości usługiPętla odpytywania portu/stanu z `sleep 1` na próbę
Interwał wysokiej precyzji (kompensacja dryftu)Odwołanie do zegara monotonicznego z obliczonym `sleep`
Opóźnienie poniżej sekundy na Alpine/BusyBoxUnikaj; używaj całkowitoliczbowych sekund lub zmień obraz bazowy

Kluczowe wnioski techniczne

  • Zawsze używaj `sleep "$VARIABLE"` z podwójnymi cudzysłowami, aby zapobiec błędom podziału słów, gdy zmienna zawiera wartość dziesiętną.
  • Preferuj `sleep 1m 30s` nad `sleep 90` dla czytelności w długo działających skryptach konserwacyjnych.
  • Uruchamiaj `sleep` w tle z `wait` i `trap` zawsze, gdy skrypt musi reagować na sygnały podczas pauzy.
  • Nigdy nie używaj hardkodowanego `sleep` jako substytutu właściwej kontroli gotowości — używaj pętli odpytywania z limitem czasu.
  • Sprawdzaj zachowanie `sleep` na docelowym systemie operacyjnym przed wdrożeniem skryptów używających wartości zmiennoprzecinkowych lub składni z wieloma argumentami.
  • Na serwerach produkcyjnych rejestruj znacznik czasu przed i po długich wywołaniach `sleep`, aby wykryć dryft harmonogramu w analizie po incydencie.
  • Podczas budowania automatyzacji na Panelach Sterowania VPS, sprawdź, czy harmonogram zadań panelu już zapewnia kontrolę interwałów, zanim ręcznie dodasz logikę `sleep`.

FAQ

Czy `sleep` zużywa CPU podczas oczekiwania?

Nie. `sleep` wywołuje `nanosleep()` (lub odpowiednik) na poziomie jądra, umieszczając proces w stanie przerywalnego uśpienia (`S` w wynikach `ps`). Nie zużywa żadnych cykli CPU podczas oczekiwania — jedynie niewielką ilość pamięci dla wpisu procesu w tablicy procesów.

Jaka jest maksymalna wartość akceptowana przez `sleep`?

W GNU/Linux, `sleep` akceptuje wartości do limitów liczby zmiennoprzecinkowej `double`, co jest praktycznie nieograniczone dla celów praktycznych. `sleep 1d` (86400 sekund) jest powszechne; `sleep 365d` jest prawidłowe. Praktycznym limitem jest czas działania systemu.

Dlaczego `sleep 0.5` nie działa w moim kontenerze Docker?

Alpine Linux używa BusyBox, którego implementacja `sleep` akceptuje tylko całkowitoliczbowe sekundy. Przejdź na obraz bazowy Debian lub Ubuntu, lub zainstaluj GNU coreutils (`apk add coreutils`), aby włączyć obsługę wartości dziesiętnych.

Czy mogę anulować działający w tle proces `sleep`?

Tak. Przechwyć jego PID za pomocą `SLEEP_PID=$!` natychmiast po uruchomieniu w tle, a następnie użyj `kill "$SLEEP_PID"`, aby go zakończyć. Jeśli użyłeś `( sleep N && command ) &`, zabicie PID podpowłoki uniemożliwi również uruchomienie kolejnego polecenia.

Czy `sleep` jest bezpieczne do użycia w skrypcie `ExecStart` jednostki usługi `systemd`?

Tak, ale z zastrzeżeniami. Jeśli jednostka usługi ma ustawione `TimeoutStartSec`, długie `sleep` podczas uruchamiania spowoduje, że systemd zakończy usługę jako nieudany start. W przypadku opóźnień po uruchomieniu, użyj `ExecStartPost` z odpytywaniem gotowości lub skonfiguruj `Type=forking` z właściwym zarządzaniem plikiem PID, zamiast polegać na `sleep` do odroczenia inicjalizacji.

15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij