Buy this tutorial as a PDF for only $5!
19 Jan 2018
A 'sleep' substitute which gives regular updates
sleep command can be quite useful in an interactive shell. If you want to check something in 5 minutes time, or even just want a timer for a while, a simple "
sleep 5m ; curl http://localhost/test.php" or just "
sleep 5m ; echo Ready" can be handy terminal tricks.
However, once you've set it off, it's not easy to tell how long it's been running for.
This shell script takes a second parameter, which allows you to specify how often you want to get updates on the sleep process. You can also add a message to display each time it checks in.
Here, we ask it to
sleep for 20 seconds, and give an update every 9 seconds. Every 9 seconds, until the 20 seconds are up, it says "Waiting for the ghost in the shell...", because that is the message we asked it to display:
(Note: The original Unix
sleep only took an integer number of seconds, eg "
sleep 300" to sleep for 5 minutes (300 seconds). Most current
sleep implementations can understand "10s", or "20m" or "2h" as "10 seconds," "20 minutes," and "2 hours" respectively).
How it works
The script is shown below. The script spawns two child processes which are run in the background; the first is the main "
sleep" command. The "
$!" variable stores the Process ID (PID) of the last backgrounded process. The script stores this in
$SLEEP_PID. It then starts an infinite loop ("
while :" will loop forever), which also runs in the background (note the ampersand (&) after the "
done" - this causes the whole loop to be a background process).
It makes a note of the Loop's PID so that the loop can be killed as soon as the script ends (even if you terminate the script abruptly).
wait $SLEEP_PID" causes the whole script to block until the sleep has finished; the two background processes keep on running.
The loop will display a message (including the current time), and sleep until its next message is due. It will keep doing this forever, or until it is killed.
trap 'kill -9 $LOOP_PID' 0" will kill the Loop if the script is terminated for any reason. Otherwise, the loop might keep writing to your terminal forever!
Once the main
sleep has finished, the "
wait $SLEEP_PID" is signalled by the operating system, and the script continues to the next command, which is to
echo a final "Done" message to tell you that it has finished.
The codeDownload sleepy.sh
#!/bin/bash if [ "$#" -eq "0" ] || [ "$1" == "-?" ]; then echo "Usage: `basename $0` sleeptime frequency [message]" echo "Sleep for
, notify every " exit 2 fi SLEEPTIME=$1 FREQUENCY=$2 shift 2 MESSAGE=$@ # Start the main sleep process sleep "$SLEEPTIME" & # Note the PID of the sleep process SLEEP_PID=$! while : do echo "`date` $MESSAGE" sleep $FREQUENCY done & # The while loop runs in its own subshell, and # has its own PID. Make a note of the loop's PID: LOOP_PID=$! # Kill the loop if we exit for any reason trap 'kill -9 $LOOP_PID' 0 # Wait for the main sleep to finish wait $SLEEP_PID # Finished. echo "`date` $MESSAGE : Done."
Getting the timing right
Note in the example above, that the script started at 27 seconds past the minute, and finished 20 seconds later, at 47 seconds past the minute, even though it was reporting in 9 second intervals; 27+9=36, then 45, then 2 seconds later, the 20 seconds have elapsed. Because the script is put together in the way it is, the "
wait $SLEEP_PID" is triggered immediately, and the loop is killed via the
trap which was set for it. The
trap is needed in case the script is interrupted, but it also neatly kills the loop for us on a normal completion, so there is no need to kill the loop even on a clean exit.
Tying it all up
At the top of the article, it was suggested to use this in tandem with another command; here is an example of this in use. After the sleep has finished, it does a
curl to inspect the HTTP headers from www.shellscript.sh:
Books and eBooks
You can mail me with this form. If you expect a reply, please ensure that the address you specify is valid. Don't forget to include the simple addition question at the end of the form, to prove that you are a real person!