How to Sleep for Milliseconds in Bash/Ksh: Cross-Platform Sub-Second Delay Techniques


3 views

While the standard sleep command works well for whole seconds, many modern scripting scenarios require finer-grained timing:

# Standard second-based sleep
sleep 1  # Wait one second

On most modern Unix-like systems (Linux, macOS), the sleep command accepts fractional seconds:

# Sub-second sleep examples
sleep 0.1   # 100ms delay
sleep 0.01  # 10ms delay
sleep 0.001 # 1ms delay (theoretical minimum)

Older Unix systems (Solaris, some BSD variants) typically reject fractional arguments. Here are alternative approaches:

Using usleep (Microsecond Sleep)

# Available on many systems (not POSIX standard)
usleep 100000  # 100ms = 100,000 microseconds

Perl One-Liner

perl -e 'select(undef,undef,undef,0.1)'  # 100ms delay

Python Alternative

python -c 'import time;time.sleep(0.1)'  # 100ms delay

This function automatically selects the best available method:

millisleep() {
    # Try fractional sleep first
    sleep 0.001 2>/dev/null && return
    
    # Fallback to usleep if available
    if command -v usleep >/dev/null; then
        usleep $(($1 * 1000))
        return
    fi
    
    # Final fallback to perl
    perl -e 'select(undef,undef,undef,'${1}'/1000)'
}

# Usage:
millisleep 100  # Sleep for 100 milliseconds

Important notes about sub-second sleep precision:

  • Actual precision depends on system scheduler (typically ~1-10ms)
  • Very short sleeps (under 10ms) may be unreliable
  • For high-precision timing, consider specialized tools or languages

When implementing frequent short delays:

  • Forking external commands (perl/python) has overhead
  • For tight loops, consider rewriting in a single language
  • Test actual timing with time command

While the sleep command is universally available in Unix-like systems, its behavior varies significantly when dealing with fractional seconds. Linux and macOS systems typically accept decimal values:

# Works on Linux/macOS
sleep 0.1  # 100ms delay
sleep 0.01 # 10ms delay

However, traditional Unix systems like Solaris and some BSD variants reject this syntax, considering it invalid.

Here are several cross-platform solutions that work across different Unix-like systems:

1. Using Perl or Python

When you have scripting languages available, they provide precise timing:

# Perl solution
perl -e 'select(undef,undef,undef,0.1);'

# Python solution
python -c 'import time;time.sleep(0.1)'

2. Using usleep (Microsecond Sleep)

Many systems provide usleep which takes microseconds:

usleep 100000  # 100ms (100,000 microseconds)

Note: usleep is deprecated in newer systems in favor of nanosleep, but remains widely available.

3. Using read with timeout

A pure shell solution using bash/ksh built-ins:

# Bash/Ksh solution
read -t 0.1 < /dev/null

For Solaris specifically, you might need to use:

# Solaris solution (if /usr/bin/sleep doesn't support decimals)
/usr/xpg4/bin/sleep 0.1

Here's how different methods compare in terms of accuracy:

# Test script to compare methods
start=$(date +%s.%N)
sleep 0.1
end=$(date +%s.%N)
echo "Native sleep: $(echo "$end - $start" | bc) seconds"

start=$(date +%s.%N)
perl -e 'select(undef,undef,undef,0.1);'
end=$(date +%s.%N)
echo "Perl sleep: $(echo "$end - $start" | bc) seconds"

Consider these factors when selecting an approach:

  • System portability requirements
  • Available utilities/languages
  • Precision needed (millisecond vs microsecond)
  • Performance overhead

For most modern systems, the native sleep with decimal support is preferable when available. For maximum compatibility, the Perl/Python solutions or usleep are good alternatives.