Re: A couple of scripting queries

brian_at_aljex.com
Date: 03/25/05


Date: 24 Mar 2005 23:59:47 -0800

sco stock "date" doesn't do that, only gnu date, which can be had on
sco a number of different ways.
On old boxes the easiest is probably to just install sh-utils-2.0 from
skunkware since doing so won't require any other large library updates.
This gets you /usr/local/bin/date, which is gnu date.

Or you can install gnutools which gets you /usr/gnu/bin/gdate, but
installing that may require installing a lot of other things first. I
prefer gnutools because I use a lot of things that are in it or that
require it and so I always install all that other stuff on all my boxes
anyways (gwxlibs, oss646c, oss642a, xorg.. ) but if you don't plan on
using a lot of new gnu utils in general and just need this one thing,
then the older skunkware package is a lot simpler and quicker.

For the "double variable" what you want is an array, and unfortunately
plain sh does not have them.
ksh and bash definitely do and probably other newer bourne shells like
ash and zsh do.
You can use a variable as the index in an array, which works just like
what you tried to do.
You can use any substitution in fact, such as a math expression even,
and since we'd have to be in ksh or bash anyways, there are more, and
more convenient, and more efficient cpu-wise math expressions. In plain
sh you have to fire up a stand alone binary, usually expr or bc or
possibly awk, whereas some common simple things ksh can do itself.

You can use ksh you know. The warning you get from cron about cron
using sh is meaningless. If you put "#!/bin/ksh" as the very first line
in the script, then ksh runs the script. If you don't specify any
shell, then sh is used in the case of cron and most users.

That said, I don't think you actually need any arrays anyways.

I think this does what you want and I didn't use any arrays. But I can
describe them if you
try this and it turns out I missed something and arrays will be the
answer.
You may have to adjust the "+%...." formats to match the way dates
happen to be stored in your database. This example produces dates
formatted as "mm/dd/yy" which is a crummy format but unfortunately the
most common here in the US. But you can make date output any kind of
format you want.
I'm using ksh here not for arrays but primarily for the $((math
expression)) and the typeset -i (actually I used the built-in alias
"integer") but a plain sh version I'll show later is very little
different.

----------[ top of file ]-----------
#!/bin/ksh

MONTHS=11

integer months=${1:-$MONTHS} || exit 1
alias gdate=/usr/local/bin/date
d=`gdate +%d`
n=0
while [ $n -le $months ] ; do
        [ $n = 0 ] && {
                SD=`gdate -d "-1 days" +%m/%d/%y`
        } || {
                SD=`gdate -d "+$n months" +%m/01/%y`
        }
        ED=`gdate -d "+$((n+1)) months -$d days" +%m/%d/%y`

        echo "select <something> from <something>\
                where date_required between \"${SD}\" and \"${ED}\""\
                | dbaccess data -
        n=$((n+1))
done
----------[end of file]----------

Here is a very talkative walk through explaining what all just
happened...

----------[top of file]----------
#!/bin/ksh
# make the script run in ksh not "whatever the callers current shell
is"
# note, except for this all my remaining comments will come before
# the bit of code they talk about, but the line above, which looks
# like a comment, must be the very first line or else it actually will
be
# just a comment

# it's just as easy, easier, to have the loop count up a variable and
# wait for it to match some other variable, and a lot more useful,
# than a static 1 to 11 list, and since this is at least a little
# likely to change once in a while, make it like a nice user config
option
# at the top of the file that can be edited now and then conveniently,
# possibly even by ordinary mortals.
MONTHS=11

# purely because it's so easy to add, provide another convenience
# even though it may never get used.
# If you run the script with no command line arguments, ("thescript")
# it will do 11 months.
# If you run the script with a numerical command line argument,
("thescript 6")
# it will do that number of months instead of the default 11.
# If a command line override is given but it's not an integer,
("thescript frank")
# then the script ends gracefully & harmlessly right here
# rather than find out the hard way what that might do to the rest of
the loop
# or to the informix database
# This reads as:
# Put the value of arg 1 if any, else the value of MONTHS, into an
integer-only variable months if possible, else exit the script with
errorlevel set to 1
integer months=${1:-$MONTHS} || exit 1

# get todays day of the month all by itself
# we'll need it later but I'll describe why when we get there...
d=`gdate +%d`

# start a "month" counter and think of "now" as "month 0"
n=0

# I could write /usr/local/bin/date several times,
# or I could describe all the things you'd have to do
# to have a "gdate" command that works everywhere including in cron,
# (PATH in /etc/profile, installing oss642a so you can edit PATH
# in /etc/default/cron, creating g.. symlinks in /usr/local/bin)
# or I could just do this...
alias gdate=/usr/local/bin/date

# run the following as long as n is less than or equal to months
while [ $n -le $months ] ; do

# figure out the starting date
# the first iteration of the loop is "now" which is "month 0"

# if n = 0 then ...
        [ $n = 0 ] && {

# so, in the case of "month 0" we want the starting date to be
# yesterday (today minus one day)
                SD=`gdate -d "-1 day" +%m/%d/%y`

# else
        } || {

# in all other cases we want the starting date to be
# the first day of the month, n months from now
                SD=`gdate -d "+$n months" +%m/01/%y`

# end of "if n = 0"
        }

# in all cases we want the ending date to be
# the last day of the month, n months from now
# the easy way to get this without some kind of lookup table
# and still being wrong on leap years etc...
# is to take advantage of gnu dates offset ability and get:
# n+1 months from today, (24th of month n+1)
# minus todays day of the month (last day of month n)
# it may help to see a version of the command with values in place of
the variables
# and expressions:
# say we are in the 3rd iteration of the loop
# working on the month of 3 months from today
# and say today is the 24th of this month
# it comes out looking like this
# gdate -d "+4 months -24 days" +%y/%m/%d
        ED=`gdate -d "+$((n+1)) months -$d days" +%m/%d/%y`

# run the db query
        echo "select <something> from <something>\
                where date_required between \"${SD}\" and \"${ED}\""\
                | dbaccess data -

# incriment n by 1
        n=$((n+1))

# end of while loop
done
---------[end of file]----------

You never have to know or care how many days are in any particular
month.
You never have to know or care about exceptions like leap years.
The boss can say "gimme 18 months from now on" and it's no problem.
The boss can say "gimme from now to the end of the year from now on" ,
ie: the number of months changes all the time, and it's a pretty small
change to get that automatically too.

Just for the heck of it
Here is a version that doesn't even require ksh and will run in plain
sh.

----------[ top of file ]-----------

MONTHS=11

months=${1:-$MONTHS}
expr ${months} + 0 >/dev/null || exit 1

gdate() { /usr/local/bin/date "$@" ; }
d=`gdate +%d`
n=0
while [ $n -le $months ] ; do
        [ $n = 0 ] && {
                SD=`gdate -d "-1 days" +%m/%d/%y`
        } || {
                SD=`gdate -d "+$n months" +%m/01/%y`
        }
        m=`expr $n + 1`
        ED=`gdate -d "+$m months -$d days" +%m/%d/%y`

        echo "select <something> from <something> \
                where date_required between \"${SD}\" and \"${ED}\"" \
                | dbaccess data -
        n=`expr $n + 1`
done
----------[end of file]----------

Brian K. White -- brian@aljex.com -- http://www.aljex.com/bkw/
+++++[>+++[>+++++>+++++++<<-]<-]>>+.>.+++++.+++++++.-.[>+<---]>++.
filePro BBx Linux SCO Prosper/FACTS AutoCAD #callahans Satriani



Relevant Pages

  • Re: bullet proof for loop over $(find) in bash, how?
    ... : In ksh, perhaps. ... so shouldn't be used in a script. ... Bash is not standard. ... OP is using bash and arrays, ...
    (comp.unix.shell)
  • Re: VG mirroring
    ... Host level migration of EMC frames for HPUX. ... hpux.vgclean - Per volume group clean-up script. ... Initialize the tables by running "ksh hpux.start". ... Look at inq.*.txt to see what devices come from what frame. ...
    (comp.unix.admin)
  • Re: [Long] about ksh93 (Was: Bourne Shell Programming on Windows)
    ... :>: Are you saying that David Korn is an unitiated or ignorant ksh ... :> won't be called in a script. ... :> in every shell. ... that should be teached in every shell programming book. ...
    (comp.unix.shell)
  • Re: vi horizontal split screen
    ... I'm an old ksh hacker, but bash will do fine. ... I started on the SysV R2 Bourne shell, and used csh for a better ... Several ksh improvements were designed to make it faster and more efficient at processing scripts, and one way to do that was substitute built-ins for external commands called from the script. ...
    (comp.editors)
  • Re: Ksh output garbled/out-of-sync
    ... is starting to look like a problem withksh. ... affected systems and running the test script). ... It turned to be a bug in ksh. ...
    (comp.unix.solaris)

Quantcast