date conversion DD-MMM-YY to YYYYMMDD - date

How to convert DD-MMM-YY to YYYYMMDD
I am in AIX, using korn shell.
neither date --date nor date -d works in aix.

pure ksh:
convert_date () {
typeset -l date=$1
typeset IFS="-"
set -- $date # now $1 is the day, $2 is the lower-case month, $3 is the year
typeset months
set -A months "" jan feb mar apr may jun jul aug sep oct nov dec
typeset -i m=1
while [[ $m -le 12 ]]; do
if [[ "$2" = "${months[$m]}" ]]; then
break
else
m=$(( m+1 ))
fi
done
# assume this century
printf "20%02d%02d%02d\n" "$3" $m "$1"
}
convert_date 06-JUL-11 # ==> 20110706

If you have tclsh on your system:
old="06-JUL-11"
new=$( echo "puts [clock format [clock scan $old] -format %Y%m%d]" | tclsh )
echo $new # ==> 20110706

I did it in perl, the hard way
sub formatDate_YYYYMMDD
{
my $date=shift;
my ($day,$mon,$yr) = split /\-/,$date;
my #months=qw(JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC );
$i=0;
foreach $_ (#months)
{
$i++;
if (/$mon/i){$mon=$i;}
}
$year=2000+$yr;
$mon=sprintf "%02d",$mon;
print "Invalid month format $date present in $file_name" if $mon ==0;
return("$year$mon$day");
}

Related

prevent globbing of argument to bash script

I want to invoke the "find" command inside myscript, using the arguments that I pass to myscript. But if I use wildcard characters with the "-name" argument and any file happens to match the string, the string is expanded to all the filenames, no matter what kind of "quotes" I 'use'.
In the shell, I want globbing, but not when I pass arguments to this script. Example:
~/u/tmp/JNK> ls -latTr
total 32
drwxr-xr-x 160 BNW staff 5440 Jan 27 18:47:37 2018 ../
-rw-r--r-- 1 BNW staff 0 Jan 27 19:30:10 2018 Henry-James.txt
-rw-r--r-- 1 BNW staff 0 Jan 27 19:30:17 2018 Emily-Dickinson.txt
-rw-r--r-- 1 BNW staff 0 Jan 27 19:30:21 2018 for-Henry-James.txt
-rwxr-xr-x 1 BNW staff 97 Jan 27 19:31:55 2018 myscript*
-rw-r--r--# 1 BNW staff 6148 Jan 27 19:43:15 2018 .DS_Store
drwxr-xr-x 2 BNW staff 68 Jan 27 19:44:51 2018 DIRECTORY/
lrwxr-xr-x 1 BNW staff 19 Jan 27 19:45:09 2018 softlink# -> for-Henry-James.txt
drwxr-xr-x 9 BNW staff 306 Jan 27 19:45:09 2018 ./
~/u/tmp/JNK> find . -type f
./.DS_Store
./Emily-Dickinson.txt
./for-Henry-James.txt
./Henry-James.txt
./myscript
~/u/tmp/JNK> find . -type f -name "*James*"
./for-Henry-James.txt
./Henry-James.txt
~/u/tmp/JNK> cat myscript
#!/bin/bash
for arg in $#
do
printf '%s' "arg="
printf '%s' "$arg"
printf '\n'
done
find . $#
~/u/tmp/JNK> ./myscript -type f
arg=-type
arg=f
./.DS_Store
./Emily-Dickinson.txt
./for-Henry-James.txt
./Henry-James.txt
./myscript
~/u/tmp/JNK> ./myscript -type f -name "*James*"
arg=-type
arg=f
arg=-name
arg=Henry-James.txt
arg=for-Henry-James.txt
find: for-Henry-James.txt: unknown primary or operator
~/u/tmp/JNK> ./myscript -type f -name '*James*'
arg=-type
arg=f
arg=-name
arg=Henry-James.txt
arg=for-Henry-James.txt
find: for-Henry-James.txt: unknown primary or operator
~/u/tmp/JNK>
Is there an elegant solution?
The solution appears to be to add one line
set -o noglob
to the script. Now we have
#!/bin/bash
set -o noglob
for arg in $#
do
printf '%s' "arg="
printf '%s' "$arg"
printf '\n'
done
find . $#
and
~/u/tmp/JNK> ./myscript -name "*Jam*"
arg=-name
arg=*Jam*
./for-Henry-James.txt
./Henry-James.txt
~/u/tmp/JNK>

How to set Last-Modified date of HTTP head via shell script

I want to set the last modified date of a file on a remote HTTP server to a shell script variable.
CATEGORIES_DATE=$(date -d "$(curl -s -I -u ${URL} | grep Last-Modified | SOMETHING HERE)" +%Y-%m-%d)
The server is responding with: Last-Modified: Sat, 28 Jul 2012 09:15:30 GMT and I want to have CATEGORIES_DATE=2012-07-28 in the end.
You can use awk + date:
CATEGORIES_DATE="$(curl -s -I "${URL}" | awk '/^Last-Modified:/ { DATE=$3 " " $4 " " $5 ; system( "date -d \"" DATE "\" \"+%Y-%m-%d\"" ) }' )"
Awk will extract the required fields and feed them to date.

Formatting localtime() in perl script

Wondering how to format the output of localtime() to year/month/day
I was able to do it easily using the 'date' command from terminal but I need to calculate previous dates as well, which I've figured out how to do in perl.
foreach my $i (0..7)
{
my $date = localtime(time() - 60*60*24*$i);
print "$i day(s) ago: $date\n";
}
Prints out this :
0 day(s) ago: Tue Apr 3 12:01:13 2012
1 day(s) ago: Mon Apr 2 12:01:13 2012
2 day(s) ago: Sun Apr 1 12:01:13 2012
3 day(s) ago: Sat Mar 31 12:01:13 2012
4 day(s) ago: Fri Mar 30 12:01:13 2012
5 day(s) ago: Thu Mar 29 12:01:13 2012
6 day(s) ago: Wed Mar 28 12:01:13 2012
7 day(s) ago: Tue Mar 27 12:01:13 2012
Here's an example of POSIX::strftime:
use POSIX ();
my #local = ( localtime )[0..5];
foreach my $i ( 0..7 ) {
my $date = POSIX::strftime( '%a %b %d %H:%M:%S %Y', #local);
print "$i day(s) ago: $date\n";
$local[3]--;
}
If you are doing date math, use a module that does it right. For instance, DateTime:
use DateTime;
my $date = DateTime->now;
foreach my $i ( 0 .. 10 ) {
$date->subtract( days => 1 );
say $date->ymd( '/' );
}
you could use POSIX::strftime from POSIX module.
perl -mPOSIX -e 'printf POSIX::strftime("%Y/%m/%d",localtime).
Script:
#!/usr/bin/perl
use strict;
foreach my $i (0..7)
{
my ($d, $m, $y) = (localtime(time() - 60*60*24*$i))[3,4,5];
printf "%d day(s) ago: %d/%d/%d\n", $i, $y+1900, $m+1, $d;
}
Output:
0 day(s) ago: 2012/4/3
1 day(s) ago: 2012/4/2
2 day(s) ago: 2012/4/1
3 day(s) ago: 2012/3/31
4 day(s) ago: 2012/3/30
5 day(s) ago: 2012/3/29
6 day(s) ago: 2012/3/28
7 day(s) ago: 2012/3/27

How do I convert epoch time to normal time in Perl?

I am attempting to write a Perl script that parses a log where on each line the second value is the date. The script takes in three arguments: the input log file, the start time, and the end time. The start and end time are used to parse out a certain value on each line that that falls between those two times. But to properly run this I am converting the start and end time to epoch time. The problem I am having is that to convert the loops 'i' value back to normal time to compare against the log file. After running localtime($i) I print the value and only see a reference printed not the actual value.
Here is the script I have so far (it is a work in progress):
#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;
use Time::localtime;
use File::stat;
my $sec = 0;
my $min = 0;
my $hour = 0;
my $mday = 0;
my $mon = 0;
my $year = 0;
my $wday = 0;
my $yday = 0;
my $isdst = 0;
##########################
# Get the engine log date
##########################
my $date = `grep -m 1 'Metric' "$ARGV[0]" | awk '{print \$2}'`;
($year,$mon,$mday) = split('-', $date);
$mon--;
#########################################
# Calculate the start and end epoch time
#########################################
($hour,$min,$sec) = split(':', $ARGV[1]);
my $startTime = timelocal($sec,$min,$hour,$mday,$mon,$year);
($hour,$min,$sec) = split(':', $ARGV[2]);
my $endTime = timelocal($sec,$min,$hour,$mday,$mon,$year);
my $theTime = 0;
for (my $i = $startTime; $i <= $endTime + 29; $i++) {
#print "$startTime $i \n";
$theTime = localtime($i);
#my $DBInstance0 = `grep "$hour:$min:$sec" "$ARGV[0]"`;# | grep 'DBInstance-0' | awk '{print \$9}'`;
#print "$DBInstance0\n";
print "$theTime\n";
}
print "$startTime $endTime \n";
The output looks like:
Time::tm=ARRAY(0x8cbbd40)
Time::tm=ARRAY(0x8cbc1a0)
Time::tm=ARRAY(0x8cbbe80)
Time::tm=ARRAY(0x8cbc190)
Time::tm=ARRAY(0x8bbb170)
Time::tm=ARRAY(0x8cbc180)
Time::tm=ARRAY(0x8cbbf30)
Time::tm=ARRAY(0x8cbc170)
Time::tm=ARRAY(0x8cbc210)
Time::tm=ARRAY(0x8cbc160)
1275760356 1275760773
I only have access to the core Perl modules and am unable to install any others.
You can use ctime, depending on your definition of "Normal time":
Example code:
use Time::Local;
use Time::localtime;
my $time=timelocal(1,2,3,24,6,2010);
print "$time\n";
$theTime = ctime($time);
print "$theTime\n";
Result:
1279954921
Sat Jul 24 03:02:01 2010
Also, you don't need to use Time::Localtime (which is why you get Time::tm instead of a standard array/string from Perl's internal localtime):
use Time::Local;
my $time=timelocal(1,2,3,24,6,2010);
print "$time\n";
$theTime = localtime($time);
print "$theTime\n";
1279954921
Sat Jul 24 03:02:01 2010
Don't forget to subtract 1900 from the year!
Remember that in scalar context, localtime and gmtime returns a ctime-formatted string, so you could use it as in the following. If that's unsuitable, you might want to use strftime from the POSIX module.
#! /usr/bin/perl
use warnings;
use strict;
use Time::Local;
my $start = "01:02:03";
my $end = "01:02:05";
my $date = "2010-02-10";
my($year,$mon,$mday) = split /-/, $date;
$mon--;
$year -= 1900;
my($startTime,$endTime) =
map { my($hour,$min,$sec) = split /:/;
timelocal $sec,$min,$hour,$mday,$mon,$year }
$start, $end;
for (my $i = $startTime; $i <= $endTime + 29; $i++) {
print scalar localtime($i), "\n";
}
print "$startTime $endTime \n";
Tail of the output:
Wed Feb 10 01:02:26 2010
Wed Feb 10 01:02:27 2010
Wed Feb 10 01:02:28 2010
Wed Feb 10 01:02:29 2010
Wed Feb 10 01:02:30 2010
Wed Feb 10 01:02:31 2010
Wed Feb 10 01:02:32 2010
Wed Feb 10 01:02:33 2010
Wed Feb 10 01:02:34 2010
1265785323 1265785325

perl help to parse log file based on time input

Perl newbie here. I have a log file that I need to parse out "Backup succeeded" and any "Error:" entries. I tried parsing the log file by using unix cat and piping it to grep. I got the information that I want, but I would like try this in perl and to also have the option to pass a date parameter and give me the lines based on the date I need.
Sample of log file output: (Backup succeeded)
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: flush-logs-time=00:00:00
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: backup-time=06:14:23
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: backup-status=Backup succeeded
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: Backup succeeded
Sample of log file output: (Error:)
Wed Jun 09 05:00:03 2010: rip1.mil.mad:backup:ERROR: mysql-zrm appears to be already running for this backupset
Wed Jun 09 05:00:03 2010: rip1.mil.mad:backup:ERROR: If you are sure mysql-zrm is not running, please remove the file /etc/mysql-zrm/rip1.mail.mad/.mysql-zrm.pid and restart mysql-zrm
**I would like a text and/or email with this information. Like so, but with the option to pass in the date I need.
Wed Jun 09 05:00:03 2010: rip1.mil.mad:backup:ERROR: mysql-zrm appears to be already running for this backupset
Wed Jun 09 05:00:03 2010: rip1.mil.mad:backup:ERROR: If you are sure mysql-zrm is not running, please remove the file /etc/mysql-zrm/rip1.mail.mad/.mysql-zrm.pid and restart mysql-zrm
Wed Jun 09 06:14:25 2010: db2.cal.mil.mad:backup:INFO: backup-status=Backup succeeded
If you would please provide me with some perl code and/or ideas to get started. I would appreciate the help. Thank you.
#!/usr/bin/perl
# usage example: <this script> Jun 09 2010 <logfile>
use strict;
use warnings;
my ($mon,$day,$year) = ($ARGV[0],$ARGV[1],$ARGV[2]);
open(FH,"< $ARGV[3]") or die "can't open log file $ARGV[3]: $!\n";
while (my $line = <FH>) {
if ($line =~ /.* $mon $day \d{2}:\d{2}:\d{2} $year:.*(ERROR:|Backup succeeded)/) {
print $line;
}
}
Here's a simple script. The file name to scan and the target date are hard-coded. Matches are printed to STDOUT.
BTW, this code is totally untested. I typed it into the text box in my browser.
use strict;
use warnings;
my $logpath = './bar/log';
my $target = 'Jun 09 2010';
open my $fh, '<', $logpath or die "Error opening $logpath $!\n";
while (my $line = <$fh> ) {
next unless date_match( $target, $line );
next unless my $result = got_error($line) // got_backup($line);
print $result;
}
sub got_backup {
my $line = shift;
return unless $line =~ /backup-status=Backup succeeded/;
return $line;
}
sub got_error {
my $line = shift;
return unless $line =~ /:ERROR:/;
return $line;
}
# Take a line and a target date. Compare the date derived from the line to
# the target, and returns true if they match.
# Also always returns true if target is not defined
sub date_match {
my $target = shift;
my $line = shift;
return 1 unless defined $target; # Always true if target is undefined.
# Where did that god-awful date format come from? Yech.
my $date = extract_date($line);
return $date eq $target;
}
# Simple extract of date using split and join with extra variables
# to make it newbie friendly.
# IMO, it would be a good idea to switch to using DateTime objects and
# DateTime::Format::Strptime
sub extract_date {
my $line = shift;
my #parts = split /:/, $line;
my $date = join ':' #parts[0..2];
#parts = split /\s+/, $date;
$date = #parts[1,2,4];
return $date;
}
You can use Getopt::Long to get a filename and target date.
It would be a good idea to use a more robust date/time parsing and comparison scheme. DateTime and friends are very good, powerful modules for date manipulation. Check them out.
If you are processing tons of data and need to be more efficient, you can avoid copying $line everywhere in a number of ways.
For future reference, if you post a little code, you'll get better responses