2025-01-30
6 min read

How to Sleep for Milliseconds in Bash and Linux

How to Sleep for Milliseconds in Bash and Linux

You need to add a short delay in your script - not a full second, just a fraction of one. How do you sleep for milliseconds in Bash?

TL;DR

Modern versions of sleep (GNU coreutils) support fractional seconds: sleep 0.5 for half a second, sleep 0.001 for 1 millisecond. For older systems, use usleep 1000 for 1 millisecond (1000 microseconds) or sleep 0.001 if available. In scripts, sleep with decimal values works on most Linux distributions. For sub-millisecond precision, use programming languages like Python or C instead of shell scripts.

Adding precise delays is useful for rate limiting, polling, animations, or avoiding race conditions in scripts.

The standard sleep command on modern Linux accepts fractional seconds:

# Sleep for half a second (500ms)
sleep 0.5

# Sleep for 100 milliseconds
sleep 0.1

# Sleep for 1 millisecond
sleep 0.001

This works with GNU sleep (default on most Linux distributions).

Checking if Your Sleep Supports Decimals

Test if your sleep command supports fractional seconds:

sleep 0.1 && echo "Fractional sleep works" || echo "Fractional sleep not supported"

Check the version:

sleep --version

If you see "GNU coreutils", fractional seconds are supported.

Using usleep for Microseconds

The usleep command (if available) takes microseconds as an argument:

# Sleep for 1000 microseconds (1 millisecond)
usleep 1000

# Sleep for 500 milliseconds
usleep 500000

# Sleep for 100 milliseconds
usleep 100000

1 millisecond = 1000 microseconds, so multiply your milliseconds by 1000.

Not all systems have usleep installed by default. On some systems, it's deprecated in favor of sleep with decimal values.

Converting Between Units

Quick reference for time conversions:

# 1 second = 1000 milliseconds = 1000000 microseconds

# 100 milliseconds
sleep 0.1          # or usleep 100000

# 50 milliseconds
sleep 0.05         # or usleep 50000

# 10 milliseconds
sleep 0.01         # or usleep 10000

# 1 millisecond
sleep 0.001        # or usleep 1000

Practical Example: Rate Limiting

Make 10 API requests with 200ms between each:

#!/bin/bash

for i in {1..10}; do
    curl -s https://api.example.com/data?page=$i
    echo "Request $i complete"
    sleep 0.2  # 200ms delay
done

This prevents overwhelming the API with rapid requests.

Practical Example: Progress Animation

Create a simple loading animation:

#!/bin/bash

echo -n "Loading"
for i in {1..20}; do
    echo -n "."
    sleep 0.1  # 100ms between dots
done
echo " Done!"

Output:

Loading.................... Done!

Practical Example: Retry Logic with Backoff

Retry a command with exponential backoff:

#!/bin/bash

MAX_RETRIES=5
DELAY=0.1  # Start with 100ms

for attempt in $(seq 1 $MAX_RETRIES); do
    if curl -sf https://api.example.com/health > /dev/null; then
        echo "Service is up!"
        exit 0
    fi

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

    # Double the delay for next attempt
    DELAY=$(echo "$DELAY * 2" | bc)
done

echo "Service did not respond after $MAX_RETRIES attempts"
exit 1

Using Perl for Precise Delays

If sleep doesn't support decimals and usleep isn't available, use Perl:

# Sleep for 150 milliseconds
perl -e 'select(undef, undef, undef, 0.15)'

# Sleep for 1 millisecond
perl -e 'select(undef, undef, undef, 0.001)'

The select function with null file descriptors acts as a precise sleep.

Using Python for Delays

Python's time module provides reliable millisecond delays:

# Sleep for 250 milliseconds
python3 -c 'import time; time.sleep(0.25)'

# Sleep for 1 millisecond
python3 -c 'import time; time.sleep(0.001)'

This works consistently across platforms.

Timing Precision Limitations

Shell sleep commands have limitations:

  • Actual sleep time may be longer than requested due to scheduling
  • Very short sleeps (<10ms) are less accurate
  • System load affects precision
  • For sub-millisecond precision, use compiled languages

Example showing timing variability:

#!/bin/bash

echo "Testing 10ms sleep accuracy:"
for i in {1..5}; do
    START=$(date +%s%N)
    sleep 0.01
    END=$(date +%s%N)
    ACTUAL=$(( (END - START) / 1000000 ))
    echo "Iteration $i: ${ACTUAL}ms"
done

Output might show:

Testing 10ms sleep accuracy:
Iteration 1: 12ms
Iteration 2: 11ms
Iteration 3: 10ms
Iteration 4: 13ms
Iteration 5: 11ms

The actual sleep time varies slightly.

Creating a Millisecond Sleep Function

Create a helper function for cleaner scripts:

# Add to your script or ~/.bashrc

# Sleep for N milliseconds
msleep() {
    sleep $(echo "scale=3; $1/1000" | bc)
}

# Usage
msleep 250  # Sleep for 250ms
msleep 100  # Sleep for 100ms

Or without bc dependency:

msleep() {
    local ms=$1
    python3 -c "import time; time.sleep($ms/1000.0)"
}

Polling with Short Intervals

Wait for a condition with short polling intervals:

#!/bin/bash

TIMEOUT=30  # seconds
INTERVAL=0.1  # 100ms polling interval
ELAPSED=0

while [ ! -f /tmp/ready.flag ]; do
    sleep $INTERVAL
    ELAPSED=$(echo "$ELAPSED + $INTERVAL" | bc)

    if (( $(echo "$ELAPSED >= $TIMEOUT" | bc -l) )); then
        echo "Timeout waiting for ready flag"
        exit 1
    fi
done

echo "Ready flag detected after ${ELAPSED}s"

Debouncing with Delays

Debounce rapid events (useful with file watchers):

#!/bin/bash

DEBOUNCE_TIME=0.5  # 500ms
LAST_EVENT=0

handle_event() {
    local current=$(date +%s%N)
    local elapsed=$(echo "scale=3; ($current - $LAST_EVENT) / 1000000000" | bc)

    if (( $(echo "$elapsed < $DEBOUNCE_TIME" | bc -l) )); then
        echo "Debouncing event (too soon)"
        return
    fi

    echo "Processing event at $(date)"
    LAST_EVENT=$current
}

# Simulate events
for i in {1..5}; do
    handle_event
    sleep 0.2  # Events every 200ms
done

Benchmarking with Millisecond Precision

Measure execution time in milliseconds:

#!/bin/bash

START=$(date +%s%N)

# Your command here
ls -R /usr > /dev/null

END=$(date +%s%N)
ELAPSED=$(( (END - START) / 1000000 ))

echo "Operation took ${ELAPSED}ms"

Sleep in Loops

Add delays between loop iterations:

#!/bin/bash

# Process items with 500ms delay between each
for item in file1.txt file2.txt file3.txt; do
    echo "Processing $item..."
    process_file "$item"
    sleep 0.5
done

This prevents resource exhaustion and gives you time to observe progress.

Interactive Delays

Add delays to make output more readable:

#!/bin/bash

echo "Starting deployment..."
sleep 0.5

echo "Pulling latest code..."
git pull
sleep 0.5

echo "Installing dependencies..."
npm install
sleep 0.5

echo "Building application..."
npm run build
sleep 0.5

echo "Deployment complete!"

The delays give users time to read each step.

Alternative: Using read with Timeout

For interactive scripts, use read with timeout:

# Wait 0.5 seconds or until user presses Enter
read -t 0.5 -p "Press Enter to continue or wait 0.5s..."

This combines a delay with the option to skip it.

When Not to Use Sleep

Avoid sleep for:

  • Waiting for network operations (use timeouts in the command itself)
  • Synchronizing concurrent processes (use locks or signals)
  • High-precision timing (use a programming language)

Better alternatives:

# Instead of sleeping and hoping, use curl's timeout
curl --max-time 5 https://api.example.com

# Instead of sleeping between checks, use inotify for file changes
inotifywait -e create /tmp/

# Instead of sleeping in loops, use proper event handling

For millisecond delays in Bash, use sleep 0.1 (100ms) or sleep 0.001 (1ms) on systems with GNU sleep. For older systems, use usleep with microseconds, or fall back to Python/Perl for cross-platform compatibility. Remember that shell sleep is not highly precise for very short intervals.

Published: 2025-01-30|Last updated: 2025-01-30T09:00:00Z

Found an issue?