Sleep until specified time It's sometimes useful to pause until a specified time (but inconvenient to use at or the like), so I wrote a tiny script to wait until a user-specified time point is reached.

I use this when I want to keep the output of preceding and subsequent commands together, but I don't mind blocking the current terminal.  Quite often, this would be M-xcompile when I want to wait until after new source code/data have been uploaded, but still have the results in a compilation-mode buffer.

Although it's a very short script, my time at Code Review has taught me that almost any program has something that can be improved, so please make your suggestions!

#!/bin/sh

# Sleep until the specified time

# Accepts any date/time format accepted by 'date'

# Assumes GNU date and GNU sleep

die() {
    echo "$@" &gt;&amp;2
    exit 1
}

usage() {
    echo "Usage: $0 TIME"
}


test $# = 1 || die $(usage)

case "$1" in
    --version)
        echo "sleep_until version 1.0"
        exit 0
        ;;
    --help)
        usage
        exit 0
        ;;
    -*)
        die "Unrecognised option: $1"
        ;;
    *)
        end=$(date -d "$1" +%s.%N)
        now=$(date +%s.%N)
        test ${end%.*} -gt ${now%.*} || die "$1 is in the past!"
        exec sleep $(echo $end $now - p | dc )
        ;;
esac


Notes:


We need GNU date for its -d option and a good range of input formats.
GNU sleep handles fractional seconds; we could remove .%N from the date formats to work with traditional/POSIX sleep.
I've used dc for the arithmetic so we can use plain sh rather than requiring a more heavyweight shell.
In a program comment it is said that the program

# Accepts any date/time format accepted by 'date'


That information should be printed with the usage help, plus one or two examples. Something like


$ ./sleep_until.sh --help
Usage: ./sleep_until.sh TIME

    TIME can be any date/time as accepted by date(1).

Examples:

    ...    


That'll save me from looking into the source code (and possibly from
looking up man date) in order to figure out the correct parameters.



Due to the truncation in 

test ${end%.*} -gt ${now%.*} || die "$1 is in the past!"


there is a (albeit small) chance that a valid date is not recognized.
This can be avoided by computing the delay first, and then checking
it to be positive (e.g. as in How to compare to floating point number in a shell script):

end=$(date -d "$1" +%s.%N)
now=$(date +%s.%N)
delay=$(echo $end - $now | bc)
test 1 -eq $(echo "$delay &gt; 0" | bc) || die "$1 is in the past!"
exec sleep $delay


Note: I'm using bc rather than dc here just because I needed it for the check $delay &gt; 0 and found a bc-based solution first (and then I did not want to use two different tools). Also I am a little bit more familiar with bc. Some criteria are given in the Unix &amp; Linux question How is bc different from dc?, such as “bc is standardised by POSIX and so is probably the more portable of the two.”