Help understanding the script

Could someone please help me in understanding the code below:

#!/usr/bin/ksh
Month=`date|cut -c5-7`                         
Day=`date|cut -c9-10`                          
Year=`date|cut -c27-28`
Rom2Jul() { case $Month in Feb) Day=$(( $Day+31 ));;
                           Mar) Day=$(( $Day+59 ));;
                           Apr) Day=$(( $Day+90 ));;
                           May) Day=$(( $Day+120 ));;
                           Jun) Day=$(( $Day+151 ));;
                           Jul) Day=$(( $Day+181 ));;
                           Aug) Day=$(( $Day+212 ));;
                           Sep) Day=$(( $Day+243 ));;
                           Oct) Day=$(( $Day+273 ));;
                           Nov) Day=$(( $Day+304 ));;
                           Dec) Day=$(( $Day+334 ));; esac }
Rom2Jul

Current=$(( $Year*365+$Day-2 ))

PrevHostname=''
PrevBackup=0
while read input                               
do Month=${input:0:3}
   Day=${input:4:2}
   Hostname=${input:13:12}
   Rom2Jul
   if [[ ${input:9:1} = ':' ]] then Year=`date|cut -c27-28`; else Year=${input:10:2}; fi
   Backup=$(( $Year*365+$Day ))
   if [[ $PrevHostname = '' ]] then PrevHostname=$Hostname; PrevBackup=$Backup
      else if [[ $PrevHostname != $Hostname ]] then echo $PrevBackup $PrevHostname 
                                                    PrevHostname=$Hostname; PrevBackup=$Backup
              else if (( $Backup > $PrevBackup )) then PrevBackup=$Backup; fi; fi; fi; done 
echo $PrevBackup $PrevHostname 

---------- Post updated at 04:54 PM ---------- Previous update was at 04:35 PM ----------

I am specifically trying to understand the

PrevHostname=''
PrevBackup=0
while read input                               
do Month=${input:0:3}
   Day=${input:4:2}
   Hostname=${input:13:12}

Run the script by setting xtrace and verbose:-

#!/usr/bin/ksh -xv

If you have any questions even after going over the output, post it here.

Hi,

Month=${input:0:3}

In value of input variable selects characters starting from 0 to 3.
Suppose input=Hello then Month variable will have Hel as a value .

Please try yoda suggested and LinkHere

1 Like

Also, you could replace the first 17 lines of that script with:

Current=$(( $(date +%y*365+%j) ))
1 Like

That's a strange script, and it is difficult to read/understand. Try e.g. serious indentation, and the proposals given above. For your special question, see here:

PrevHostname=''                 # preset variable to empty
PrevBackup=0                    # preset variable to 0
while read input                # read variable "input" from stdin
                                # input contents:   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                # input char count:  01234567890123456789012345 
                                # result in variables:
do Month=${input:0:3}           # ABC
   Day=${input:4:2}             # DE
   Hostname=${input:13:12}      # NOPQRSTUVWX
1 Like

There is another Rom2Jul under the while loop

Should I just delete it, if I use Current=$(( $(date +%y*365+%j) ))

---------- Post updated at 12:19 PM ---------- Previous update was at 12:08 PM ----------

If I change the code to include

Current=$(( $(date +%y*365+%j) ))

I am getting "stale" message for even those which are not 3 days old. Any help/advise will be appreciated.

Thanks

The backup backup Julian date calculation is quite simple if you have GNU date available on your system.

GNU date would allow us to convert date strings in this manor:

$ date -d "Oct 7 2016"
Fri, Oct 07, 2016 12:00:00 AM

Your calculation would then simply be:

PrevHostname=''
PrevBackup=0
while read input
do
  if [[ ${input:9:1} = ':' ]] then
     DateStr="${input:0:3} ${input:4:2}"
  else
     DateStr="${input:0:3} ${input:4:2} 20${input:10:2}"
  fi
  Backup=$(( $(date -d "$DateStr" +%y*365+%j) ))

I am using AIX 7.1 and it looks like I do not have the GNU date, any other suggestion to simplify this script?

This is interesting because under this circumstances the script should not run: in AIX 7.1 the default shell is a ksh88 and as far as i know these substring-functions ${var:offset:length} are only available in ksh93, which resides in /usr/bin/ksh93 , not /usr/bin/ksh . You might want to investigate.

I hope this helps.

bakunin

It's a fine line between what you have and using perl to do the date processing. As we don't have the whole script some assumptions need to be made on what you are trying to do with these Julian values.

It appears this script is trying to calculate the age in days of particular past dates. The problem with the solution used in this script is that leap years will cause 1 day errors.

Under AIX I would propose using a perl script that tells you the age (in days) of a date eg:

$ agedays.pl "Jan 20 2016"
268

agedays.pl could be written like this:

#!/bin/perl
use POSIX;
use Time::Local;

my %mon;
@mon{qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/} = 0..11;

my ($mmm, $dd, $yy) = split(/[-\/ ]/, $ARGV[0]);

printf "%.0f", (time() - timelocal(0,0,0,$dd,$mon{$mmm}, $yy) - 0.4999) / (24*60*60);

The script then could forget about Current and just fetch the age of the backup like this:

PrevHostname=''
PrevBackup=0
while read input
do
  if [[ ${input:9:1} = ':' ]] then
     DateStr="${input:0:3} ${input:4:2} $(date +%Y)"
  else
     DateStr="${input:0:3} ${input:4:2} 20${input:10:2}"
  fi
  BackupAge=$(agedays.pl "$DateStr")
  ...

Below is the full script

#!/usr/bin/ksh
#
#   mksysb.ksh      verifies that current mksysb images are being maintained by the two mksysb (NIM) hosts,
#                   one in the DC1 and anohter in the DC2.   The program reads the available mksysb images
#                   from both hosts along with the date they were created.   Converts the creation time into
#                   a quasi-julian calendar format for comparision the current date.   Any mksysb image less
#                   than three days old is considered "current".   Older images are considered "stale".   Any
#                   system belonging to the Unix Operation team from which a mksysb can not be found is
#                   considered "missing".   
#
# while true; do                               # end-less loop - can be removed in favor of a cron entry
Month=`date|cut -c5-7`                         # break current date - "Wed Sep 23 16:33:34 EDT 2015"
Day=`date|cut -c9-10`                          # into Month(Mmm), Day(##) & Year(##)
Year=`date|cut -c27-28`
Rom2Jul() { case $Month in Feb) Day=$(( $Day+31 ));;
                           Mar) Day=$(( $Day+59 ));;
                           Apr) Day=$(( $Day+90 ));;
                           May) Day=$(( $Day+120 ));;
                           Jun) Day=$(( $Day+151 ));;
                           Jul) Day=$(( $Day+181 ));;
                           Aug) Day=$(( $Day+212 ));;
                           Sep) Day=$(( $Day+243 ));;
                           Oct) Day=$(( $Day+273 ));;
                           Nov) Day=$(( $Day+304 ));;
                           Dec) Day=$(( $Day+334 ));; esac }
Rom2Jul
Current=$(( $Year*365+$Day-2 ))                # current ddddd less 3 days to allow for delayed backups & leap year
Path=/tmp/mksysb                             # for testing ONLY!
BackupInput=$Path/mksysbChk.input
ContactNIM=/usr/local/admin/bin/remote.pl
$ContactNIM --host=NIM1 --command=/bin/'ls -al /nim/dr/mksysb/\*'|grep -e _dr -e .tgz|cut -c37-90|cut -d" " -f2-8|cut -d_ -f1 > $BackupInput     # place DC1 clients into the list
$ContactNIM --host=NIM2 --command=/bin/'ls -al /nim/dr/mksysb/\*'|grep -e _dr -e .tgz|cut -c37-90|cut -d" " -f2-8|cut -d_ -f1 >> $BackupInput   # append DC2 clients into the list
BackupMsg=$Path/mksysbChk.msg                  # setup mail strings
BackupTitle='mksysb Status Report'
BackupAdm='xxxxx@xxxx.com'
if [[ ! -s $BackupInput ]] then BackupMsg='ERROR - unable to communicate with the NIM servers and verify mksysb status - NO notifications sent'
                                mail -s "$BackupTitle" $BackupAdm < $BackupMsg; exit; fi   # connection to NIM servers lost, aborting!!!
BackupOutput=$Path/mksysbChk.output
if [[ -e $BackupOutput ]] then rm $BackupOutput; fi
PrevHostname=''
PrevBackup=0
while read input                               # eliminate duplicate mksysbChk.files & convert raw dates into yy x 365 + ddd format
do Month=${input:0:3}
   Day=${input:4:2}
   Hostname=${input:13:12}
   Rom2Jul
   if [[ ${input:9:1} = ':' ]] then Year=`date|cut -c27-28`; else Year=${input:10:2}; fi
   Backup=$(( $Year*365+$Day ))
   if [[ $PrevHostname = '' ]] then PrevHostname=$Hostname; PrevBackup=$Backup
      else if [[ $PrevHostname != $Hostname ]] then echo $PrevBackup $PrevHostname >> $BackupOutput
                                                    PrevHostname=$Hostname; PrevBackup=$Backup
              else if (( $Backup > $PrevBackup )) then PrevBackup=$Backup; fi; fi; fi; done < $BackupInput
echo $PrevBackup $PrevHostname >> $BackupOutput   # write out final record
if [[ -e $BackupMsg ]] then rm $BackupMsg; fi
SupportedHosts=/tmp/aix.lst                    # daily extract of the supported hostnames
while read Hostname                            # match supported hostnames with mksysbChk.files & determine status (current/stale/missing)
do Backup=`grep $Hostname $BackupOutput|cut -c1-5`   # actual match
   if [[ $Backup == '' ]] then echo "$Hostname\tMissing\tmksysb" >> $BackupMsg
      else if [[ $Backup < $Current ]] then echo "$Hostname\tStale\tmksysb" >> $BackupMsg; fi; fi; done < $SupportedHosts
mail -s "$BackupTitle" $BackupAdm < $BackupMsg   # for testing ONLY!

This should be OK for AIX - dont have system to test it on sorry.

#!/bin/ksh
#
#   mksysb.ksh      verifies that current mksysb images are being maintained by the two mksysb (NIM) hosts,
#                   one in the DC1 and anohter in the DC2.   The program reads the available mksysb images
#                   from both hosts along with the date they were created.   Converts the creation time into
#                   a quasi-julian calendar format for comparision the current date.   Any mksysb image less
#                   than three days old is considered "current".   Older images are considered "stale".   Any
#                   system belonging to the Unix Operation team from which a mksysb can not be found is
#                   considered "missing".   
#
# while true; do                               # end-less loop - can be removed in favor of a cron entry
Path=/tmp/mksysb                             # for testing ONLY!
BackupInput=$Path/mksysbChk.input
ContactNIM=/usr/local/admin/bin/remote.pl
$ContactNIM --host=NIM1 --command=/bin/'ls -al /nim/dr/mksysb/\*'|grep -e _dr -e .tgz|cut -c37-90|cut -d" " -f2-8|cut -d_ -f1 > $BackupInput     # place DC1 clients into the list
$ContactNIM --host=NIM2 --command=/bin/'ls -al /nim/dr/mksysb/\*'|grep -e _dr -e .tgz|cut -c37-90|cut -d" " -f2-8|cut -d_ -f1 >> $BackupInput   # append DC2 clients into the list
BackupMsg=$Path/mksysbChk.msg                  # setup mail strings
BackupTitle='mksysb Status Report'
BackupAdm='xxxxx@xxxx.com'

if [[ ! -s $BackupInput ]]
then
   BackupMsg='ERROR - unable to communicate with the NIM servers and verify mksysb status - NO notifications sent'
   mail -s "$BackupTitle" $BackupAdm < $BackupMsg
   exit
fi   # connection to NIM servers lost, aborting!!!

BackupOutput=$Path/mksysbChk.output

if [[ -e $BackupOutput ]]
then
   rm $BackupOutput
fi


PrevHostname=''
PrevBackup=1000

while read input
do
  if [[ ${input:9:1} = ':' ]]
  then
     DateStr="${input:0:3} ${input:4:2} $(date +%Y)"
  else
     DateStr="${input:0:3} ${input:4:2} 20${input:10:2}"
  fi
  BackupAge=$(agedays.pl "$DateStr")

 if [[ $PrevHostname = '' ]]
 then
      PrevHostname=$Hostname
      PrevBackup=$BackupAge
 else if [[ $PrevHostname != $Hostname ]]
      then
          echo $PrevBackup $PrevHostname >> $BackupOutput
          PrevHostname=$Hostname
          PrevBackup=$BackupAge
      else if (( $BackupAge < $PrevBackup ))
           then
               PrevBackup=$BackupAge
           fi
      fi
  fi
done < $BackupInput
echo $PrevBackup $PrevHostname >> $BackupOutput   # write out final record

if [[ -e $BackupMsg ]]
then
    rm $BackupMsg
fi
SupportedHosts=/tmp/aix.lst                    # daily extract of the supported hostnames
while read Hostname                            # match supported hostnames with mksysbChk.files & determine status (current/stale/missing)
do BackupAge=`grep $Hostname $BackupOutput|tail -1 | cut -d' ' -f 1`   # actual match
   if [[ $BackupAge == '' ]]
   then
       echo "$Hostname\tMissing\tmksysb" >> $BackupMsg
   else if [[ $BackupAge > 0 ]]
        then
           echo "$Hostname\tStale\tmksysb" >> $BackupMsg
        fi
   fi
done < $SupportedHosts
mail -s "$BackupTitle" $BackupAdm < $BackupMsg   # for testing ONLY!

Note in your script I doubt the line below would work:

do Backup=`grep $Hostname $BackupOutput|cut -c1-5`   # actual match

Firstly the $BackupOutput file would contain multiple entries for the host as it's appended each time and also the cut of the first 5 characters would not fetch the numeric julian days correctly. I've replaced this with tail -1 to get the last (most recent) entry for host and used -f option on cut to fetch the first file (being the age).

I am getting the below error, do I need to install a Perl module?

agedays.pl: not found [No such file or directory]

I do have Perl

which perl
/usr/local/bin/perl

Have a look at post 10. There is a suggestion for writing your own perldays.pl in there.

Robin

I cannot cite the output format of all the NIM-commands from memory, but i think the whole script can be replaced by one NIM-command executed. If you do a mksysb from the NIM server a resource of the type MKSYSB is created and entered into the NIMs database, which can subsequently be queried.

You will have to wait until monday when i return to office for details, but i think it will be possible to replace the whole script with a few select lines of code.

I hope this helps.

bakunin

Hello Bakunin,

Thanks for the offer to help, I look forward to hearing back from you.

Thanks

OK, being at the office and sitting in front of an xterm pointing at my NIM server does wonders for that old brain of mine ...

Here it is: you can get a list of all NIM objects of a certain type. In this case you are interested in the resources of type "mksysb". Do yourself a favour and, when you take the mksysb with NIM means, give it a proper name. In my case this means: hostname plus a suffix. Issue:

root@nim-server # lsnim -t mksysb | more
aix71_04_02                     resources       mksysb
system_1_mksysb                 resources       mksysb
system_2_mksysb                 resources       mksysb
system_3_mksysb                 resources       mksysb
[...]

If you work your NIM-server like me you perhaps have some installation-images as mksysbs which you use to instll new systems (see above, the aix71_04_02 ) and the images of the various installed LPARs you take regularly (the others in the list above). Now filter out all the installation images so that only the systems are left and cycle through them, using the -l command line option of lsnim to see the details:

# lsnim -l system_1_mksysb
system_1_mksysb:
   class         = resources
   type          = mksysb
   creation_date = Sat Oct 15 21:10:56 2016
   source_image  = system_1
   arch          = power
   Rstate        = ready for use
   prev_state    = unavailable for use
   location      = /export/mksysb/sys.mksysb
   version       = 7
   release       = 1
   mod           = 3
   oslevel_r     = 7100-03
   oslevel_s     = 7100-03
   alloc_count   = 0
   server        = master

For instance, a (quick and dirty) code fragment that lists the systems and the creation date of their respective mksysbs, supposing your naming convention is like mine, would be (remove the comments to actually run it):

lsnim -t mksysb | grep -v '^aix' |\                 # filter out install-images
while read MKSYSB junk ; do                         # read only the mksysb-names
     lpar="${MKSYSB%%_mksysb}"                      # cut off trailing "_mksysb"
     cdate=$(lsnim -l $MKSYSB |\                    # trim o/p to creation date
             sed -n '/creation_date/ s/^.*= //p' \
            )
     print - "$lpar  $cdate"                        # print results
done

I am aware that this is only the sketch of a solution, but it should be fairly straightforward to implement that into a script.

I hope this helps.

bakunin

./agedays.pl
Day '' out of range 1..31 at ./agedays.pl line 10

I am getting this error for the code below

#!//usr/local/bin/perl
use POSIX;
use Time::Local;

my %mon;
@mon{qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/} = 0..11;

my ($mmm, $dd, $yy) = split(/[-\/ ]/, $ARGV[0]);

printf "%.0f", (time() - timelocal(0,0,0,$dd,$mon{$mmm}, $yy) - 0.4999) / (24*60*60);



Hi,

Note that your script, in line number 8 expects commandline argument but you did not pass it as per your post#18.

my ($mmm, $dd, $yy) = split(/[-\/ ]/, $ARGV[0]);

Try running with arg as follows (example):

.agedays.pl /12/10/2016

Refer CPAN for more : Time::Local

Since I will be calling agedays.pl in the other script, how do I use the date with agedays.pl in the other script.