I want my bash script to sleep until a specific time. So, I want a command like \"sleep\" which takes no interval but an end time and sleeps until then.
The \"at\"-d
On Ubuntu 12.04.4 LTS here is the simple bash input which works :
sleep $(expr `date -d "03/21/2014 12:30" +%s` - `date +%s`)
Use sleep
, but compute the time using date
. You'll want to use date -d
for this. For example, let's say you wanted to wait until next week:
expr `date -d "next week" +%s` - `date -d "now" +%s`
Just substitute "next week" with whatever date you'd like to wait for, then assign this expression to a value, and sleep for that many seconds:
startTime=$(date +%s)
endTime=$(date -d "next week" +%s)
timeToWait=$(($endTime- $startTime))
sleep $timeToWait
All done!
On OpenBSD, the following could be used to compact a */5
5-minute crontab(5) job into an 00
hourly one (to make sure fewer emails are generated, all whilst performing the same task at exact intervals):
#!/bin/sh -x
for k in $(jot 12 00 55)
do
echo $(date) doing stuff
sleep $(expr $(date -j +%s $(printf %02d $(expr $k + 5))) - $(date -j +%s))
done
Note that the date(1) would also break the sleep(1) by design on the final iteration, as 60
minutes is not a valid time (unless it is!), thus we won't have to wait any extra time prior to getting our email report.
Also note that should one of the iterations take more than 5 minutes allotted to it, the sleep
would likewise graciously fail by design by not sleeping at all (due to what is a negative number interpreted as a command-line option, instead of wrapping around to the next hour or even eternity), thus making sure your job could still complete within the hour allotted (e.g., if only one of the iterations takes a little bit more than 5 minutes, then we would still have the time to catch up, without anything wrapping around to the next hour).
The printf(1) is needed because date
expects exactly two digits for the minute specification.
I put together a small utility called Hypnos to do this. It's configured using the crontab syntax and blocks until that time.
#!/bin/bash
while [ 1 ]; do
hypnos "0 * * * *"
echo "running some tasks..."
# ...
done
You could perhaps use 'at' to send a signal to your script, which sat waiting for that signal.
Here's something I wrote just now to synchronise multiple test clients:
#!/usr/bin/python
import time
import sys
now = time.time()
mod = float(sys.argv[1])
until = now - now % mod + mod
print "sleeping until", until
while True:
delta = until - time.time()
if delta <= 0:
print "done sleeping ", time.time()
break
time.sleep(delta / 2)
This script sleeps until next "rounded" or "sharp" time.
A simple use case is to run ./sleep.py 10; ./test_client1.py
in one terminal and ./sleep.py 10; ./test_client2.py
in another.