💤 sleep Command

Pause and Timing Control in Linux Shell Scripts

About the sleep Command

The sleep command suspends execution for a specified amount of time. It's one of the simplest yet most essential commands in shell scripting, used to introduce delays, control timing, implement retry logic, rate limiting, and coordinate processes. Sleep accepts time in seconds by default, but can also handle minutes, hours, and days with appropriate suffixes.

How it works: When sleep is executed, the calling process is suspended (paused) for the specified duration. The process doesn't consume CPU during this time - it's truly sleeping, not busy-waiting. After the duration expires, the process resumes execution at the next command. Sleep can be interrupted with Ctrl+C (SIGINT) or other signals, in which case it returns a non-zero exit status.

Common applications: Retry logic with backoff, rate limiting API calls, polling for status changes, animation and progress indicators, scheduled tasks, coordinating parallel processes, and testing time-dependent code.

Basic Syntax: sleep NUMBER[SUFFIX]... Time Suffixes: s seconds (default if no suffix) m minutes h hours d days Common Usage: sleep 5 # Sleep for 5 seconds sleep 2.5 # Sleep for 2.5 seconds (decimals allowed) sleep 1m # Sleep for 1 minute (60 seconds) sleep 2h # Sleep for 2 hours sleep 1d # Sleep for 1 day sleep 1m 30s # Sleep for 1 minute 30 seconds (90 seconds total) sleep 1.5m # Sleep for 1.5 minutes (90 seconds) Exit Status: 0 Successful completion >0 Error or interrupted by signal

Detailed Examples

1Basic Sleep - Simple Delays

The most common use: pausing execution for a specified time.

$ echo "Starting task..." $ sleep 3 $ echo "Task complete!"
Starting task... [3 second pause] Task complete!
$ date; sleep 5; date
Thu Nov 28 10:00:00 EST 2025 [5 second pause] Thu Nov 28 10:00:05 EST 2025
What's happening: The sleep 3 command pauses execution for 3 seconds. During this time, the shell waits - no commands execute. After 3 seconds, execution continues with the next command. Second example: Shows the actual time elapsed using date before and after the sleep. The timestamps confirm exactly 5 seconds passed. Key behavior: Sleep accepts decimal values (sleep 2.5), so you're not limited to whole seconds. The process is truly suspended - it consumes virtually no CPU while sleeping. This makes sleep efficient even for long delays. Important note: Sleep can be interrupted by signals (Ctrl+C sends SIGINT). If interrupted, sleep exits immediately with a non-zero status and the remaining time is not slept.
Use decimal seconds for sub-second delays: sleep 0.1 for 100 milliseconds, sleep 0.5 for half a second.

2Time Suffixes - Minutes, Hours, Days

Using time suffixes for better readability and convenience.

$ sleep 2m # 2 minutes $ sleep 1h # 1 hour $ sleep 1d # 1 day $ sleep 30s # 30 seconds (explicit suffix) $ sleep 1.5h # 1.5 hours (90 minutes)
#!/bin/bash # Backup script with notification delay echo "Starting backup..." ./backup.sh echo "Backup complete. Notification in 5 minutes..." sleep 5m notify-send "Backup Complete" "Your backup finished successfully."
What's happening: Sleep accepts time suffixes for better readability: s (seconds), m (minutes), h (hours), d (days). Default: If no suffix is provided, seconds are assumed. Decimals work with suffixes: sleep 1.5h sleeps for 1 hour 30 minutes (5,400 seconds). Readability advantage: sleep 1h is much clearer than sleep 3600. In scripts, this self-documenting code helps maintainability. Script example: After a backup completes, wait 5 minutes before showing a notification. This gives time for additional tasks or lets the system settle. Using 5m instead of 300 makes the intent immediately clear to anyone reading the code.
Combine multiple time units: sleep 1h 30m sleeps for 1.5 hours. Sleep adds them together: 3600 + 1800 = 5400 seconds total.
Time suffixes are a GNU extension. On some Unix systems, only numeric seconds are supported. Check your system's sleep with man sleep.

3Retry Logic with Exponential Backoff

Implementing robust retry mechanisms with increasing delays.

#!/bin/bash # Retry a command with exponential backoff max_attempts=5 attempt=1 base_delay=1 while [ $attempt -le $max_attempts ]; do echo "Attempt $attempt of $max_attempts..." if curl -sf https://api.example.com/health > /dev/null; then echo "Success!" exit 0 fi if [ $attempt -lt $max_attempts ]; then delay=$((base_delay * 2 ** (attempt - 1))) echo "Failed. Retrying in ${delay} seconds..." sleep $delay fi ((attempt++)) done echo "All attempts failed." exit 1
Attempt 1 of 5... Failed. Retrying in 1 seconds... Attempt 2 of 5... Failed. Retrying in 2 seconds... Attempt 3 of 5... Failed. Retrying in 4 seconds... Attempt 4 of 5... Failed. Retrying in 8 seconds... Attempt 5 of 5... Success!
What's happening: This implements exponential backoff - delays increase exponentially with each retry (1s, 2s, 4s, 8s, 16s). Why exponential backoff? If a service is overloaded, constant retries make it worse. Exponential backoff gives the service time to recover while not hammering it with requests. The calculation: delay = base_delay * 2^(attempt-1) generates the sequence 1, 2, 4, 8, 16... Pattern breakdown: (1) Try the operation. (2) If successful, exit. (3) If failed and attempts remain, calculate delay and sleep. (4) Increment attempt counter and loop. Real-world application: This pattern is used extensively in distributed systems, API clients, database connections, and network operations where transient failures are common. The exponential backoff prevents overwhelming a struggling service while still providing reasonable retry attempts.
Add jitter (randomness) to backoff to prevent thundering herd: sleep $((delay + RANDOM % 5)) adds 0-4 random seconds.

Real API Retry Example

retry_with_backoff() { local max_attempts=5 local timeout=1 local attempt=1 while [ $attempt -le $max_attempts ]; do if "$@"; then return 0 fi echo "Attempt $attempt failed. Retrying in ${timeout}s..." sleep $timeout timeout=$((timeout * 2)) ((attempt++)) done return 1 } # Usage: retry_with_backoff curl -sf https://api.example.com/data

4Polling and Status Checking

Repeatedly check for a condition with delays between checks.

#!/bin/bash # Wait for a service to become ready max_wait=60 # Maximum 60 seconds elapsed=0 interval=2 echo "Waiting for service to start..." while [ $elapsed -lt $max_wait ]; do if curl -sf http://localhost:8080/health > /dev/null 2>&1; then echo "Service is ready! (after ${elapsed}s)" exit 0 fi echo "Not ready yet... (${elapsed}s elapsed)" sleep $interval elapsed=$((elapsed + interval)) done echo "Timeout: Service did not start in ${max_wait} seconds" exit 1
Waiting for service to start... Not ready yet... (0s elapsed) Not ready yet... (2s elapsed) Not ready yet... (4s elapsed) Service is ready! (after 6s)
What's happening: This polling pattern repeatedly checks if a service is ready, with 2-second delays between checks. Key elements: max_wait prevents infinite loops - after 60 seconds, give up. interval controls how often to check (every 2 seconds). elapsed tracks total time waited. The pattern: Check condition → if met, exit success → if not, wait and try again → respect timeout. Common use cases: Waiting for containers to start, database connections to be available, files to appear, processes to complete, or services to become healthy. Advantages over busy-wait: Sleep releases CPU between checks. Without sleep, the loop would run continuously, wasting CPU cycles. With sleep, the process is truly suspended, making efficient use of system resources. This pattern is essential in container orchestration, deployment scripts, and integration tests.
Adjust polling interval based on expected startup time. Fast services: 1s. Slow services: 5-10s. Balance responsiveness vs. excessive checks.

5Rate Limiting and Throttling

Control the rate of operations to avoid overwhelming systems.

#!/bin/bash # Fetch data from API with rate limiting (max 10 requests/second) items=(item1 item2 item3 item4 item5 item6 item7 item8 item9 item10) delay=0.1 # 100ms between requests = 10 requests/second for item in "${items[@]}"; do echo "Fetching $item..." curl -s "https://api.example.com/data/$item" > "${item}.json" sleep $delay done echo "All items fetched with rate limiting"
#!/bin/bash # Process files with throttling to avoid I/O saturation for file in /data/*.csv; do echo "Processing $(basename "$file")..." ./process_large_file.sh "$file" # Give I/O subsystem time to catch up sleep 2 done
What's happening: Rate limiting prevents overwhelming target systems with too many requests. First example: Enforces 10 requests per second by sleeping 0.1 seconds (100ms) between each API call. This respects API rate limits and prevents being throttled or banned. Calculation: 1 second / 10 requests = 0.1 seconds per request. For 5 requests/second, use sleep 0.2. Second example: Processes large files with 2-second pauses between them, preventing I/O saturation. When processing huge files, continuous reads/writes can overwhelm disk I/O or network storage. Brief pauses let the I/O subsystem catch up, caches flush, and other processes get resources. Real-world importance: Many APIs have rate limits (GitHub: 5000/hour, Twitter: varies by endpoint). Rate limiting in your code prevents HTTP 429 errors and IP bans. For file processing, it prevents system slowdown and allows other processes to function normally.
Calculate rate limit delay: delay = 1 / requests_per_second. For 100 requests/min: delay = 60 / 100 = 0.6 seconds.

Batch API Processing with Rate Limit

#!/bin/bash # Process 1000 items at 50 requests/second delay=0.02 # 1/50 = 0.02 seconds for id in $(seq 1 1000); do curl -s "https://api.example.com/item/$id" & # Every 50 requests, wait 1 second if [ $((id % 50)) -eq 0 ]; then wait # Wait for background jobs sleep 1 fi done

6Progress Indicators and Animation

Create simple progress indicators and animations with timed delays.

#!/bin/bash # Spinner animation spinner="/-\|" for i in {1..20}; do printf "\r${spinner:i%4:1} Processing..." sleep 0.1 done printf "\r✓ Complete! \n"
/ Processing... - Processing... \ Processing... | Processing... ... ✓ Complete!
#!/bin/bash # Progress bar with percentage total=50 for i in $(seq 1 $total); do percent=$((i * 100 / total)) bar=$(printf '%*s' "$((i * 40 / total))" '' | tr ' ' '=') printf "\r[%-40s] %d%%" "$bar" "$percent" sleep 0.1 done echo ""
[========================================] 100%
#!/bin/bash # Countdown timer for i in {10..1}; do echo -ne "\rStarting in $i seconds... " sleep 1 done echo -e "\rStarting now! "
What's happening: Sleep creates timing for visual feedback during long operations. First example: Spinner animation using sleep 0.1 for smooth rotation. The spinner string "/-\|" rotates through characters, and \r returns cursor to line start for overwriting. Second example: Progress bar that fills gradually. Each iteration adds a section to the bar and updates the percentage. sleep 0.1 makes it visible; without it, the bar would complete instantly. Third example: Countdown timer using sleep 1 for one-second intervals. Why this matters: Long-running operations without feedback make users think the program froze. Visual progress indicators with appropriate sleep delays provide reassurance that work is happening. The timing must balance visibility (too fast is useless) with not slowing down the actual work unnecessarily.
Use sleep 0.05 for smooth animations, sleep 0.1 for moderate speed, sleep 0.2 or more for slower, visible updates.

7Scheduled Task Execution

Simple scheduling without cron, useful for one-off delayed tasks.

#!/bin/bash # Execute a command after a delay (simple at-like functionality) echo "Task scheduled to run in 1 hour..." sleep 1h echo "Executing scheduled task..." ./backup.sh echo "Scheduled task complete!"
#!/bin/bash # Schedule multiple tasks with different delays (sleep 30; echo "30-second task") & (sleep 1m; echo "1-minute task") & (sleep 2m; echo "2-minute task") & echo "All tasks scheduled. Waiting for completion..." wait echo "All scheduled tasks complete!"
#!/bin/bash # Daily task runner (runs forever) while true; do echo "Running daily backup at $(date)" ./daily_backup.sh # Sleep for 24 hours sleep 1d done
What's happening: Sleep enables simple scheduling without cron. First example: One-time delayed execution - wait 1 hour, then run backup. This is simpler than cron for one-off tasks. Second example: Multiple scheduled tasks running in parallel using background jobs (&). Each sleeps for its delay, then executes. The main script waits for all to complete. Third example: Infinite loop for recurring tasks. Runs backup, sleeps 24 hours, repeats forever. This is useful in containers where cron might not be available or desired. Advantages over cron: No cron configuration needed, works in containers, easier to understand for simple cases, can use script variables for dynamic timing. Disadvantages: Not as robust as cron (no persistence across reboots), no built-in error handling, single point of failure. Best for: Container entrypoint scripts, simple recurring tasks, one-off delayed execution, development/testing.
Long-running sleep commands (hours/days) in scripts should handle signals properly. Consider adding signal handlers or using systemd timers for production scheduling.

8Coordinating Parallel Processes

Using sleep to stagger process starts and avoid resource contention.

#!/bin/bash # Launch parallel workers with staggered starts num_workers=5 delay=2 for i in $(seq 1 $num_workers); do echo "Starting worker $i..." ./worker.sh "$i" & # Stagger starts to avoid resource spike [ $i -lt $num_workers ] && sleep $delay done echo "All workers started. Waiting for completion..." wait echo "All workers finished!"
#!/bin/bash # Graceful shutdown with delays echo "Sending TERM signal to all workers..." pkill -TERM worker echo "Waiting 30 seconds for graceful shutdown..." sleep 30 # Force kill any remaining processes if pgrep worker > /dev/null; then echo "Force killing remaining workers..." pkill -KILL worker sleep 2 fi echo "Shutdown complete"
What's happening: Sleep coordinates timing between parallel processes. First example: Launches 5 workers with 2-second delays between starts. This prevents all workers from starting simultaneously and competing for resources (CPU, memory, database connections, file handles). Staggered starts smooth out resource usage. Without delays, 5 workers starting simultaneously might cause CPU spike, memory pressure, or connection pool exhaustion. Second example: Graceful shutdown pattern. Send TERM signal, wait 30 seconds for clean exit, then force KILL if needed. The sleep gives processes time to finish current work, flush buffers, close connections, and exit cleanly. Why this matters: Parallel processing is common (batch jobs, data pipelines, web scrapers), but poorly coordinated parallelism causes problems. Staggered starts and graceful shutdowns with appropriate sleep delays make systems more reliable and maintainable.
Calculate stagger delay based on startup cost. Heavy database connections: 5-10s. Light HTTP requests: 0.5-1s. Balance parallelism vs. resource spikes.

9Testing and Simulation

Simulating delays and timing-dependent behavior for testing.

#!/bin/bash # Simulate slow network response simulate_api() { local delay=$((RANDOM % 5 + 1)) # 1-5 seconds echo "API call received, processing..." sleep $delay echo '{"status": "success", "data": "result"}' } # Test timeout handling timeout 3 bash -c 'simulate_api' if [ $? -eq 124 ]; then echo "Request timed out (as expected)" fi
#!/bin/bash # Simulate processing pipeline with stages stages=("Loading data" "Parsing" "Transforming" "Validating" "Saving") timings=(2 3 5 2 1) for i in "${!stages[@]}"; do echo "${stages[$i]}..." sleep "${timings[$i]}" echo " ✓ Complete" done
#!/bin/bash # Load testing with controlled request timing requests_per_second=10 duration=60 # Run for 60 seconds start_time=$(date +%s) request_count=0 while [ $(($(date +%s) - start_time)) -lt $duration ]; do curl -s http://localhost:8080/api/endpoint > /dev/null & ((request_count++)) sleep $(echo "scale=3; 1/$requests_per_second" | bc) done wait echo "Sent $request_count requests in $duration seconds"
What's happening: Sleep is essential for testing timing-dependent code. First example: Simulates slow API responses with random 1-5 second delays. Tests timeout handling by using timeout 3 - if the simulated API takes longer than 3 seconds, timeout kills it and returns exit code 124. This validates that your code properly handles timeouts. Second example: Simulates a multi-stage data pipeline where each stage takes different amounts of time. Useful for testing progress indicators, demonstrating workflow to stakeholders, or validating pipeline orchestration. Third example: Load testing tool that maintains precise request rate using calculated sleep intervals. sleep $(echo "scale=3; 1/10" | bc) computes 0.1 seconds (100ms) for 10 requests/second. Testing importance: Many bugs only appear under specific timing conditions. Sleep lets you recreate those conditions: slow networks, resource contention, race conditions, timeout scenarios. Without controlled delays, timing bugs are hard to reproduce and fix.
For microsecond precision in tests, use sleep 0.001 (1ms). Most systems support down to millisecond precision.

10Signal Handling and Interruption

Understanding how sleep interacts with signals and interruption.

#!/bin/bash # Basic signal handling with sleep trap "echo 'Interrupted! Cleaning up...'; exit 130" INT echo "Running task (press Ctrl+C to interrupt)..." sleep 30 echo "Task completed successfully"
$ ./script.sh Running task (press Ctrl+C to interrupt)... ^CInterrupted! Cleaning up...
#!/bin/bash # Resumable sleep that handles interruption total_sleep=60 elapsed=0 trap "echo 'Interrupted at ${elapsed}s'; exit 1" INT while [ $elapsed -lt $total_sleep ]; do echo "Sleeping... (${elapsed}s / ${total_sleep}s)" sleep 1 ((elapsed++)) done echo "Sleep completed!"
#!/bin/bash # Check if sleep was interrupted echo "Sleeping for 10 seconds..." sleep 10 if [ $? -ne 0 ]; then echo "Sleep was interrupted!" exit 1 else echo "Sleep completed normally" fi
What's happening: Sleep can be interrupted by signals, and proper handling is important. First example: Uses trap to catch SIGINT (Ctrl+C). When sleep is interrupted, the trap runs cleanup code before exiting. Exit code 130 (128 + 2) indicates termination by SIGINT. Second example: Implements interruptible sleep with progress tracking. Instead of one 60-second sleep, uses 60 one-second sleeps. This allows checking progress and responding to interruption more granularly. Each iteration reports elapsed time. Third example: Checks sleep's exit status. Exit code 0 = normal completion, non-zero = interrupted or error. This allows conditional logic based on whether sleep completed. Signal behavior: When sleep receives a signal, it terminates immediately and returns non-zero exit status. The remaining sleep time is lost unless you track it yourself. Important for: Long-running scripts, graceful shutdown, cleanup operations, resumable operations, interactive scripts.
Long sleeps in scripts should handle signals appropriately. Use trap for cleanup, or break long sleeps into smaller chunks for better interruptibility and progress visibility.
For truly uninterruptible operations, use trap '' INT to ignore SIGINT temporarily, then re-enable afterward.

Time Suffix Reference

Suffix Meaning Example Equivalent in Seconds
s Seconds sleep 30s 30
m Minutes sleep 5m 300
h Hours sleep 2h 7200
d Days sleep 1d 86400
(none) Seconds (default) sleep 10 10
You can combine multiple suffixes: sleep 1h 30m 45s = 1 hour + 30 minutes + 45 seconds = 5445 seconds total.

Exit Status Codes

Exit Code Meaning Common Cause
0 Success Sleep completed normally for the full duration
1 Error Invalid argument (e.g., negative number, invalid suffix)
130 Interrupted by SIGINT User pressed Ctrl+C during sleep
143 Interrupted by SIGTERM Process received termination signal
Check exit status in scripts: if ! sleep 10; then echo "Sleep interrupted"; fi

Best Practices and Patterns

Effective Sleep Usage Guidelines

  • Use appropriate time units: Write sleep 2h not sleep 7200 for readability
  • Decimal precision for sub-second timing: Use sleep 0.1 for 100ms delays
  • Check exit status for interruption: Always check if sleep completed or was interrupted
  • Break long sleeps into chunks: Use loops with shorter sleeps for better interruptibility
  • Add sleep to prevent resource exhaustion: Rate limiting, staggered starts, polling intervals
  • Signal handling in long-running scripts: Use trap to handle cleanup when sleep is interrupted
  • Avoid busy-waiting: Always use sleep instead of empty while loops that waste CPU
  • Document sleep durations: Comment why specific delays are needed
  • Test with shorter durations: Use environment variables for sleep durations to speed up testing
  • Consider alternatives for production: cron for scheduling, systemd timers, at command, watch command

Common Anti-Patterns to Avoid

  • ❌ Busy-waiting without sleep: while true; do check_status; done wastes CPU
  • ✅ Proper polling: while true; do check_status; sleep 1; done
  • ❌ Hardcoded sleep durations: sleep 300 is unclear
  • ✅ Named durations: sleep 5m # Wait for cache refresh
  • ❌ Uninterruptible long sleeps: sleep 1d can't be interrupted gracefully
  • ✅ Chunked sleeps: Loop with shorter sleeps for better control

Common Use Cases Summary

Retry with Backoff

for i in 1 2 4 8 16; do command && break || sleep $i done

Rate Limiting

for item in "${items[@]}"; do process "$item" sleep 0.1 # Max 10/second done

Polling Until Ready

until curl -sf localhost:8080/health; do sleep 2 done

Staggered Parallel Starts

for i in {1..5}; do ./worker & sleep 2 done

Graceful Shutdown

pkill -TERM myapp sleep 30 pkill -KILL myapp 2>/dev/null

Progress Indicator

for i in {1..10}; do echo -ne "\rProgress: $i/10" sleep 0.5 done

Related Commands and Alternatives

  • watch: Execute a command repeatedly with fixed intervals - watch -n 5 command
  • timeout: Run a command with a time limit - timeout 30 command
  • at: Schedule one-time command execution at specific time
  • cron: Recurring scheduled tasks (more robust than sleep loops)
  • systemd timers: Modern alternative to cron for scheduled tasks
  • usleep: Sleep for microseconds (not standard on all systems)
  • nanosleep(): System call for precise sleep (requires programming)
  • read -t: Bash builtin for timeout with user input option

Performance Considerations

CPU Usage: Sleep consumes virtually no CPU - the process is truly suspended. This makes it efficient even for long delays or many concurrent sleeping processes.

Precision: Sleep precision depends on system timer resolution and load. Typically accurate to within a few milliseconds for short sleeps, but can drift slightly for very long sleeps on loaded systems.

System Load: Thousands of sleeping processes use minimal resources. Each sleeping process uses some memory but no CPU time.

Alternatives for High Precision: For sub-millisecond precision or real-time requirements, consider programming languages with nanosleep() or high-resolution timers.