LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   over my head in bash (https://www.linuxquestions.org/questions/programming-9/over-my-head-in-bash-897398/)

rbees 08-15-2011 08:18 AM

over my head in bash
 
Ladies & Gentlemen,

Thanks for the help in a previous post.

I am trying to write a script. I have come to a part that is over my head. This script is dependent on the hdate command which returns dates and times for specific events on the Hebrew calender. The problem is that hdate does not account for daylight savings time.

One of the things the script does is to schedule events via 'at' to occur at #certain times of the day, hence the need to have the script adjust for daylight #savings time.

I have the following code started but I am at a loss as to how to continue.

What I need is some help to understand how to get where I need to go, not just #write the code for me.

$ date returns day-of-week, month, day, hour:min:sec, time zone indicator, year

the format of the tzdump is the same.

It occurred to me this morning that I can narrow the test because I can eliminate #all months except March and November (for my area) as one side or the other. With that in mind....

Code:

function daylightSavings  #  Zone data is in /usr/share/zoneinfo
{
daylightOff=( 12 01 02 03 );                # need to fill these via the Zone Data
daylightOn=( 05 06 07 08 09 10)                # no clue how.  This is one of those later things.
if [ date +%m=={$daylightOff[*]} ];
  then return;
elif [ date +%m=={$daylightOn[*]} ];  # kmails color formating indicators tell me there is a problem with this line but I can't find it.
  then $mytime+1;        # need to fix this to access the correct part of the time variable, but for now this will work if it actually does what I think.
  then return;
elif [ date +%m `zdump -v US/Michigan|grep `date +%Y`` ];
  # would be nice if date would would return "2nd sunday of the month" but I don't see how without getting fancy.
  test for month;
    if advance month;  # spring ahead
      then;        # I know that this will not work.  It is only to follow the logic.
        if;
          test for before time change;
        then return;
        elif;
        test for after time change;
          then $mytime+1;
          return;
        fi;
    elif retard month;        # fall back
      then;
        if;
          test for before time change;
          then $mytime+1;
        then return;
        elif;
        test for after time change;
        then return;
        fi;
fi;
}

Thanks.

grail 08-15-2011 08:57 AM

SO I am at a bit of loss trying to understand what is going on. So I have a questions instead.

You mention in your explanation about how hdate does not handle daylight saving and yet your example only uses date which based on setting the correct time zone
I was of the understanding that daylight saving was factored in? Hence if your machine is aligned to /usr/share/zoneinfo/US/Michigan does it not perform the necessary
daylight savings when required?

David the H. 08-15-2011 01:49 PM

date +%z will give you your offset from UTC. I don't live in a country with daylight savings time though, so I don't know if this gets adjusted for the shift.

The date info page says this, however:
Quote:

`%z'
RFC 2822/ISO 8601 style numeric time zone (e.g., `-0600' or
`+0530'), or nothing if no time zone is determinable. This value
reflects the numeric time zone appropriate for the current time,
using the time zone rules specified by the `TZ' environment
variable.

(Emphasis mine.)

And like grail, I'd like to know more about how hdate displays its output, and what you really want your script to do. Not in code, but in terms of human function.

MTK358 08-15-2011 01:58 PM

Quote:

Originally Posted by David the H. (Post 4443736)
date +%z will give you your offset from UTC. I don't know if this gets adjusted for the shift.

I just tried it, and it looks like it does adjust for daylight savings time.

gnashley 08-15-2011 02:07 PM

Code:

elif [ date +%m=={$daylightOn[*]} ];  # kmails color formating indicators tell me there is a problem with this line but I can't find it.
  then $mytime+1;        # need to fix this to access the correct part of the time variable, but for now this will work if it actually does what I think.
  then return;

You have two 'then's under one 'if'

rbees 08-15-2011 02:21 PM

grail,

my example only references date and not hdate because it is the current date that I am using to adjust the time given by hdate.

Quote:

then $mytime+1; # need to fix this to access the correct part of the time variable, but for now this will work if it actually does what I think.
The "mytime" variable is set elsewhere in the script by hdate and only needs to be increased if daylight savings time is active.

David the H and MTK358,

I do like the idea of adjusting the time output by hdate by using the time zone. I think that will be much simpler in the script over all because hdate uses a time zone variable that is simpler to change in my script than the actual time. So I will rewrite with that in mind. Thanks.

Now it is just the last part with all the logic.

More on the general purpose later when I have some time.

rbees 08-15-2011 02:24 PM

Quote:

Originally Posted by gnashley (Post 4443754)
You have two 'then's under one 'if'

duhh, that would explain it. thanks I guess I have some rewriting to do.

rbees 08-16-2011 06:57 AM

Thanks for the help.

A brief example of what I am trying to do with the script:

Test the date to see if it is a Friday or Saturday. If Friday then find out via hdate what time sundown is (18 min before actually) and schedule a shofar (rams horn) blast to be played at that time to anounce the beginnig of the Sabbath. Then the same basic thing for the end of the Sabbath and the Jewish Holidays.

So if the shofar blast is scheduled without accounting for daylight savings time it will be at the wrong time. Hdate uses the time zone to get the correct offset from Jeruselem for your local location. So if I set my time zone varible early in the script no mater when I access hdate ater that the time will be correct and I won't have to continually test the date every time I want to schedule an event.

Code:

function daylightSavings  #  Zone data is in /usr/share/zoneinfo
{
daylightOff=( 12 01 02 03 );                # need to fill these via the Zone Data
daylightOn=( 05 06 07 08 09 10)                # no clue how.  This is one of those later things.
advance=( 04 )
retard=( 11 )
if [[ `date +%m` == ${daylightOff[*]} ]];  # does not appear to work
  then return;
elif [[ `date +%m` == ${daylightOn[*]} ]];  # does not appear to work
  then $tz+1;        # time zone variable, set elseware in the script.
                # results  bash: -5+1: command not found
  return;
elif [ `date +%m` == `zdump -v US/Michigan` | grep `date +%Y` ];
  test for month;
    if advance month;  # spring ahead
      then;        # I know that this will not work.  It is only to follow the logic.
        if;
          test for before time change;
        then return;
        elif;
        test for after time change;
          then $tz+1;        # tz set elseware in script
          return;
        fi;
    elif retard month;        # fall back
      then;
        if;
          test for before time change;
          then $tz+1;        # tz set elseware in script
        then return;
        elif;
        test for after time change;
        then return;
        fi;
fi;
}

So working my way through the code my first test does not work. My guess would be that {$daylightOn[*]} does not step through the items in the aray right. I have tried a couple of variations with no joy. I don't have time to play anymore now but I wanted to post this for you.
Code:

daylightOff=( 12 01 02 03 );
daylightOn=( 05 06 07 08 09 10)
if [[ `date +%m` == ${daylightOn[*]} ]];
  then echo "I work";
fi

I think I need to do something like "for item in ${daylightOn} do"

Thanks

lej 08-16-2011 08:15 AM

You shouldn't need to calculate this manually.

I do not have hdate so I don't know what the output format is, but if it's compatible with date, you can use date to automatically correct for DST using the -d option.

For example, as I write this, the current time is (I'm in the UK):

Quote:

# date
Tue Aug 16 14:13:32 BST 2011
Now, if hdate ignores DST, its output would presumably be (assuming same format as date?):

Tue Aug 16 13:13:32 GMT 2011

Feeding this back into date will print the specified date but corrected for local time:

Quote:

# date -d "Tue Aug 16 13:13:32 GMT 2011"
Tue Aug 16 14:13:32 BST 2011
You can then pull out the hours/minutes as needed.

Of course, if hdate's output format differs, you may need to modify the string somewhat. For example, if you make it print just the time, you could add this to the rest of the date string, something like:

Quote:

date -d "$(date "+%a %b %d $(hdate <print time>) XXX %Y")"
(Replace XXX with your equivalent of GMT.)

grail 08-16-2011 09:51 AM

Also for the array tests ... you were close but of course one month is not equal to several, but several can contain one:
Code:

daylightOff=( 12 01 02 03 )
daylightOn=( 05 06 07 08 09 10)

if [[ ${daylightOn[*]} =~ $(date +%m) ]]
then
    echo "I work";
fi

Also your first if and elif have the same test but different outcomes, ie return compared to $tz + 1 (which won't work by the way) and then return.

michaelk 08-16-2011 08:15 PM

According to the man pages the -c option will output Shabat start/stop times but will assume it will only display on Fri and Sa so I can not see the output format. It also states the start times are based on 20 min vs 18 before sunset.

As already stated you can easily get the UTC offset value adjusted for daylight saving time for your time zone from date and then plug it into hdate to get the sunset times based on your location (latitude, longitude).

Example sunrise/sunset times for Kansas City on 16 Aug 2011
date +%:::z
-05
hdate -s -l 39 -L 94 -z -05
6:29 - 20:11

Please post your script when you get it working.

rbees 08-17-2011 06:58 AM

Thanks

So starting again.

lej

Code:

:~$ hdate -c -L-85 -l44 -z-5 19 08 2011
Friday, 19 August 2011, 19 Av 5771
, (19:20)

:~$ hdate -t -L-85 -l44 -z-5 19 08 2011
Friday, 19 August 2011, 19 Av 5771
, first light: 04:11
talit: 04:45
sun rise: 05:47
mid day: 12:43
sun set: 19:40
first stars: 20:11
three stars: 20:27

# different switches cause radically different output so passing the actual time output to date to have it converted seams more work to me. But then I am just beginning to get a feel for bash scripting. I can see before not to much longer I am going to have to beat my head on the sed/awk wall for awhile. Then I may change my mind about that.

grail thanks for the pointer on having the parameters in the right order.

I think you my be missing that there are 2 different tests one for those months that are before daylight savings time starts and one for those months after it ends. In one case I need make no change and the other increment the $tz variable by one. It does occur to me that at some point I will need to do some error checking to be sure that the variable returns to the normal state when daylight savings time ends.

What is the difference between == and =~ ? At one point I was looking at a page that listed some of those kinds of things but can't find it now.

Someone on irc mentioned that using date +%Z to get the time zone may be a better way to go. But I want to work on the logic as a learning experience for now.

working on my code.

thanks

grail 08-17-2011 07:32 AM

Quote:

I think you my be missing that there are 2 different tests one for those months that are before daylight savings time starts and one for those months after it ends.
My bad ... misread that :(

== - test if the left and right of the expression are equal

=~ - regular expression test, left matches expression on the right

David the H. 08-17-2011 05:12 PM

Another way to think about it:

== matches globbing patterns, and the entire string must be compared as a whole.

=~ matches regex patterns, and so can match substrings. It can even extract them for later use with the BASH_REMATCH array variable.

The first is simpler to use and faster to process, while the latter is more powerful and flexible. I personally mentally translate them as "X equals Y (==)", and "X contains Y (=~)".

This page shows the various options in [ and [[:
http://mywiki.wooledge.org/BashFAQ/031


It doesn't seem to me that +%Z would be appropriate at all. DST is a very region-specific thing, and just because a person is in X time zone does not mean he's in an area that uses DST. Not to mention that even when they do use it, different countries apply it at different times. Since DST is already factored into +%z, it should be a much more accurate measurement of the local time.

Not that I understand exactly what you're doing, but one possibility, if you want to avoid the "radically different outputs", is to just set up a single hdate function that always outputs everything it's capable of producing in a consistent fashion. Then you can parse that output for the actual data you need in your script's subsequent operations.

rbees 08-17-2011 08:19 PM

Thanks guys

First let me apologize for not listening and understanding.

I have changed the tz variable in my script form being statically set to -5 to being computed at runtime via `date +%:::z` and hence all the times given by hdate will be corrected for daylight saving time.

Sorry I am so thick headed David the H and MTK358. I guess I just needed the example shown by michaelk to understand what you were trying to tell me. But the process did get me to where I needed to go.

So as requested here is the full code of the script as it now stands. Bare in mind that it is a work in progress and needs much work to be really usable.

Code:

#!/bin/bash

# Script to play a Shofar blast for the start of Shabbat among other things

##### Constants

lat=44                # change to your latitude
long=-85        # change to your longitude
tz=`date +%:::z`
day=()
month=()
year=()
Day=()
havdalah=()

##### Functions

function long        # not used yet
{
  6        # dummy data
    # I want to set this via an address in a config file and pull the gps off the web
}

function lat        # not use yet
{
  7        # dummy data
}

function day_of_week        #set the day of the week
{
if [ `date +%a` == "Fri" ];
  then Day=`date +%a`;
  else Day=`date -d "next fri" +%a` ;
fi
}

function set_date
{
  # Get the current date and set the the variabls day, month, year.
  day=`date +%d -d "next $Day"`;
  month=`date +%m -d "next $Day"`;
  year=`date +%Y -d "next $Day"`;
}

function set_shabbat        # error checking
{
day=`date -d "next sat" +%d`
}

function torah_reading        # Shabbat reading
{
set_shabbat;
parsha=`hdate -r $day $month $year`;
echo "The Parsha for $parsha";
}

function havdalah        # end of Shabbat
{
  havdalah=`hdate -c -L$long -l$lat -z$tz $day $month $year`;
  echo "Havdalah time for; $havdalah";
}

function candle_time        # start of Shabbat
{
  Time=`hdate -c -L$long -l$lat -z$tz $day $month $year`;
  echo "Candle lighting time for; $Time";
}

function shofar                # rams horn
{
day_of_week;
set_date;
# need to make a test to see if the shofar blast is already set.
# need to pause or cancel any other sound apps before the shofar and then restart them after.
# need to separate it from a Shabbat specific cTime to generic for use on Yom Tove

cTime=`hdate -c -L$long -l$lat -z$tz $day $month $year | grep -e '(.' | cut -d " " -f2 | sed 's/[()]//g'`;
at $cTime $month/$day/$year -f $HOME/bin/shabbat/data/shofar;
}

function yom_tove        # holidays
{
# test date for Yom Tove
1        # dummy data
}

function yom_tove_reading
{
# need to build a table to list Yom Tove readings
2        # dummy data
}

function rosh_chodesh        # new moon = new month
{
# test date for Rosh Chodesh
3        # dummy data
}

function count_omer        # 50 days between Passover and Shavuot
{
# count the Omer
4        # dummy data
}

function radio        # not implemented
{
rTime=`hdate - `; # need to determine what is the best time to start the radio.
mpg123 http://216.118.106.247:7000;
}


###### Main
clear
day_of_week
set_date
if [ "$Day" == "Fri" ];
  then candle_time;
  torah_reading;
fi;
havdalah;
shofar;
#radio; # play Internet radio station JM in the AM



All times are GMT -5. The time now is 12:47 AM.