6

I want to write a shell where given a date (day-hour-min) e.g.

10:00 AM Sun
2:30 PM Mon
...

It sleeps until that exact date & time. I thought one way of doing it is, I could get the current date and calculate the difference? then convert that into seconds and sleep for that time.

However, I am not too sure how you could do so using shell scripts?

#!/bin/bash

now=$(date '+%A %W %Y %X')
date =  2:30 PM Mon

difference = ??
sleep difference
user
  • 61

3 Answers3

8

if the user is allowed to use at command, this is the perfect use for that:

$ at 08:00 022116
at> myscript.sh
at>      <----------- ctrl-d here
job 9 at 2016-02-21 08:00

if you get a message like "user blah is not able to run at", ask the syadmin to add this user to at.allow file or remove from at.deny file, depending on how it is used in your environment.

Unless of course you wish this days long sleep happen in the middle of your script. Even then you can cut up your script into two, writing variables you want to keep, to a file and when the time comes and second part of your script executes, it can read those variables from the stored file.

glenn jackman
  • 85,964
MelBurslan
  • 6,966
3
#!/bin/bash
NOW=$(date +"%s")
SOON=$(date +"%s" -d "3:00 PM Sun")
INTERVAL=$(($SOON-$NOW))
sleep $INTERVAL

GNU date allows you to specify the format of the output, as well as the date to display. So I use the format string "%s" to get the time in seconds since the epoch, and the same for the arbitrary time using the -d paramater. Get the difference, and you have the interval to sleep.

Checking for a date in the past is left as an exercise for the reader.

DopeGhoti
  • 76,081
  • -d is a non-POSIX extension (see http://unix.stackexchange.com/a/1828/117549) – Jeff Schaller Feb 03 '16 at 19:44
  • I have added specificity with respect to GNU date. – DopeGhoti Feb 03 '16 at 19:46
  • What's the rationale behind putting the + outside the quotes around the format string? +"$s". – Digital Trauma Feb 03 '16 at 23:17
  • @Sukminder, I habitually use uppercase mainly to distinguish from builtins and binaries, which are typically lowercase (e. g. I may assign VERB and then run $VERB as a command). I am aware that there is the potential for a conflict, but I generally check my environments for such conflicts. There is no semantic difference between upper and lower, so it's largely a matter of preference. @Digital Trauma, I place the + outside of the quoted format string to visually distinguish between the formatting itself and the invocation thereof. – DopeGhoti Feb 03 '16 at 23:37
  • @JeffSchaller, is date -v POSIX, or is that a BSD extension? – DopeGhoti Feb 03 '16 at 23:49
  • http://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html#tag_20_30 – Jeff Schaller Feb 04 '16 at 00:18
  • To report on a date/time other than now in a POSIX way you should look to touch and ls if youre interested. That is, if at doesnt suit. – mikeserv Feb 04 '16 at 01:21
  • I don't think this will work correctly if the machine is suspended while sleep is running. – Vladimir Panteleev Jun 01 '18 at 06:59
1

While probably you should use at as already suggested, I sometimes find the following helpful when working with time problems. I've abridged it some, but the link is there.

Seconds Since the Epoch

A value that approximates the number of seconds that have elapsed since the Epoch. A Coordinated Universal Time name (specified in terms of seconds, minutes, hours, days since January 1 of the year, and calendar year minus 1900) is related to a time represented as seconds since the Epoch, according to the expression below.

If the year is <1970 or the value is negative, the relationship is undefined. If the year is >=1970 and the value is non-negative, the value is related to a Coordinated Universal Time name according to the C-language expression, where all variables are integer types:

s +  m*60 + h*3600 + d*86400          +
(y-70)*31536000    + ((y-69)/4)*86400 -
((y-1)/100)*86400  + ((y+299)/400)*86400

Note:

The last three terms of the expression add in a day for each year that follows a leap year starting with the first leap year since the Epoch. The first term adds a day every 4 years starting in 1973, the second subtracts a day back out every 100 years starting in 2001, and the third adds a day back in every 400 years starting in 2001. The divisions in the formula are integer divisions; that is, the remainder is discarded leaving only the integer quotient.

mikeserv
  • 58,310