RHL5 to Sunsolaries - unix

Below code works in bash but it is not working in ksh.
Presently i am using RHL5 version os below code is working fine but in sunsolaries it is not working.
In sunsolaries we are using Korn Shell.
#!/bin/bash
#give start date and enddate in the format yyyy_mm_dd
startdate="${1//_/-}" # change underscores into dashes
enddate="${2//_/-}"
enddate=`date -d "$enddate + $i day" "+%Y_%m_%d"` #Increases enddate by 1 day so that loop runs on given enddate also
enddate="${enddate//_/-}"
echo "StartDate: $startdate EndDate+1Day: $enddate"
nextdate=$startdate #nextdate runs from startdate to enddate
while [ 1 ]
do
echo "$nextdate $enddate"
if [ "$nextdate" == "$enddate" ];then #after given enddate loop breaks
break
fi
day=`date -d "$nextdate"`
arr=(${day// / })
echo "${arr[0]}"
if [ "${arr[0]}" == "Sat" ];then #checking if day is Saturday, if true then increase nextday and continue
nextdate=`date -d "$nextdate + 1 day" "+%Y_%m_%d"`
nextdate="${nextdate//_/-}"
continue
fi
#####your code begins here
echo "creating file file_$nextdate.txt"
touch "file_$nextdate.txt" #test code, just creating files with date, remove this
#####your code ends here
nextdate=`date -d "$nextdate + 1 day" "+%Y_%m_%d"` #increasing nextday by 1 day
nextdate="${nextdate//_/-}"
done
Please help me how it works in ksh
Thanks

Your script is using several time the Gnu date specific -d option. Either find a different way to achieve what it does in you use case, or install Gnu date on the Solaris machine if it isn't already.

Related

To improve Calculate Number of Days Command

Would like to generate report, which calculate the number of days, the material is in the warehouse.
The number of days is the difference between date ($3 field) the material comes in and
against (01 OCT 2014) manual feed date.
Input.csv
Des11,Material,DateIN,Des22,Des33,MRP,Des44,Des55,Des66,Location,Des77,Des88
aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj
aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj
aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj
aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj
aa,yyy,05-FEB-14.09:02:09,cc,dd,x20,ee,ff,gg,YY250,hh,jj
aa,yyy,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj
aa,zzz,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj
Currently i am using below command to popualte Ageing - No of days at $13 field ( thanks to gboffi)
awk -F, 'NR>0 {date=$3;
gsub("[-.]"," ",date);
printf $0 ",";system("date --date=\"" date "\" +%s")}
' Input.csv | awk -F, -v OFS=, -v now=`date --date="01 OCT 2014 " +%s` '
NR>0 {$13=now-$13; $13=$13/24/3600;print $0}' >Op_Step11.csv
while using the above command in Cygwin (windows), it is taking 50 minutes for 1 Lac (1,00,000) rows of sample input.
Since my actual input file contains 25 million rows of lines , it seems that the script will take couple of days ,
Looking for your suggestions to improve the command and advice !!!
Expected Output:
Des11,Material,DateIN,Des22,Des33,MRP,Des44,Des55,Des66,Location,Des77,Des88,Ageing-NoOfDays
aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj,42.6611
aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj,42.6611
aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj,109.621
aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj,109.621
aa,yyy,05-FEB-14.09:02:09,cc,dd,x20,ee,ff,gg,YY250,hh,jj,237.624
aa,yyy,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj,237.624
aa,zzz,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj,237.624
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787
I don't have the access to change the input format and dont have perl & python access.
Update#3:
BEGIN{ FS=OFS=","}
{
t1=$3
t2="01-OCT-14.00:00:00"
print $0,(cvttime(t2) - cvttime(t1))/24/3600
}
function cvttime(t, a) {
split(t,a,"[-.:]")
match("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC",a[2])
a[2] = sprintf("%02d",(RSTART+2)/3)
return( mktime("20"a[3]" "a[2]" "a[1]" "a[4]" "a[5]" "a[6]) )
}
Since you are on cygwin you are using GNU awk which has it's own built-in time functions and so you do not need to be trying to use the shell date command. Just tweak this old command I had lying around to suit your input and output format:
function cvttime(t, a) {
split(t,a,"[/:]")
match("JanFebMarAprMayJunJulAugSepOctNovDec",a[2])
a[2] = sprintf("%02d",(RSTART+2)/3)
return( mktime(a[3]" "a[2]" "a[1]" "a[4]" "a[5]" "a[6]) )
}
BEGIN{
t1="01/Dec/2005:00:04:42"
t2="01/Dec/2005:17:14:12"
print cvttime(t2) - cvttime(t1)
}
It uses GNU awk for time functions, see http://www.gnu.org/software/gawk/manual/gawk.html#Time-Functions
Here is an example in Perl:
use feature qw(say);
use strict;
use warnings;
use Text::CSV;
use Time::Piece;
my $csv = Text::CSV->new;
my $te = Time::Piece->strptime('01-OCT-14', '%d-%b-%y');
my $fn = 'Input.csv';
open (my $fh, '<', $fn) or die "Could not open file '$fn': $!\n";
chomp(my $head = <$fh>);
say "$head,Ageing-NoOfDays";
while (my $line = <$fh>) {
chomp $line;
if ($csv->parse($line)) {
my $t = ($csv->fields())[2];
my $tp = Time::Piece->strptime($t, '%d-%b-%y.%T');
my $s = $te - $tp;
say "$line," . $s->days;
} else {
warn "Line could not be parsed: $line\n";
}
}
close($fh);

How to code day of the month and send email in UNIX

I am trying to make it so if I get emailed in the first 15 days of the month, I get a 0 and if I get emailed in the second half of the month, I get a 1.
currently I have
echo date + "%e"/30 | bc -l | mailx -s "Payday yet?" blah#gmail.com
I think I'm just not familiar how to work with the date
You can use shell test command ( or [ expr ] which does the same only with an extra ] as the last argument for sake of looking like a matching pair of brackets).
Something like this should do what you want:
[ `date +'%e'` -le 15 ]; FIRST_HALF=$?; mailx -s "Payday = $FIRST_HALF"

Check the date and time entered by user in UNIX

I have a Shell script which uses the date and time parameters entered by the user.
Date as mm/dd/yyyy and Time as HH:MM .
What would be the easiest means to check the user had entered the proper date [ like month should be less than 12.... for time MM should be less than 60...
Do we have any built in functions in UNIX for checking the timestamp?
You could use the unix date tool to parse and verify it for you, and test the return code e.g.
A valid date, return code of 0:
joel#bohr:~$ date -d "12/12/2000 13:00"
Tue Dec 12 13:00:00 GMT 2000
joel#bohr:~$ echo $?
0
An invalid date, return code 1:
joel#bohr:~$ date -d "13/12/2000 13:00"
date: invalid date `13/12/2000 13:00'
joel#bohr:~$ echo $?
1
You can vary the input format accepted by date by using the +FORMAT option (man date)
Putting it all together as a little script:
usrdate=$1
date -d "$usrdate" > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Date $usrdate was valid"
else
echo "Date $usrdate was invalid"
fi
You could use grep to check that the input conforms to the correct format:
if ! echo "$INPUT" | grep -q 'PATTERN'; then
# handle input error
fi
where PATTERN is a regular expressino that matches all valid inputs and only valid inputs. I leave constructing that pattern to you ;-).
(Late answer)
Something that you can use:
...
DATETIME=$1
#validate datetime..
tmp=`date -d "$DATETIME" 2>&1` ; #return is: "date: invalid date `something'"
if [ "${tmp:6:7}" == "invalid" ]; then
echo "Invalid datetime: $DATETIME" ;
else
... valid datetime, do something with it ...
fi

Converting dates in AWK

I have a file containing many columns of text, including a timestamp along the lines of Fri Jan 02 18:23 and I need to convert that date into MM/DD/YYYY HH:MM format.
I have been trying to use the standard `date' tool with awk getline to do the conversion, but I can't quite figure out how to pass the fields into the 'date' command in the format it expects (quoted with " or 's,) as getline needs the command string enclosed in quotes too.
Something like "date -d '$1 $2 $3 $4' +'%D %H:%M'" | getline var
Now that I think about it, I guess what I'm really asking is how to embed awk variables into a string.
If you're using gawk, you don't need the external date which can be expensive to call repeatedly:
awk '
BEGIN{
m=split("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",d,"|")
for(o=1;o<=m;o++){
months[d[o]]=sprintf("%02d",o)
}
format = "%m/%d/%Y %H:%M"
}
{
split($4,time,":")
date = (strftime("%Y") " " months[$2] " " $3 " " time[1] " " time[2] " 0")
print strftime(format, mktime(date))
}'
Thanks to ghostdog74 for the months array from this answer.
you can try this. Assuming just the date you specified is in the file
awk '
{
cmd ="date \"+%m/%d/%Y %H:%M\" -d \""$1" "$2" "$3" "$4"\""
cmd | getline var
print var
close(cmd)
}' file
output
$ ./shell.sh
01/02/2010 18:23
and if you are not using GNU tools, like if you are in Solaris for example, use nawk
nawk 'BEGIN{
m=split("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",d,"|")
for(o=1;o<=m;o++){
months[d[o]]=sprintf("%02d",o)
}
cmd="date +%Y"
cmd|getline yr
close(cmd)
}
{
day=$3
mth=months[$2]
print mth"/"day"/"yr" "$4
} ' file
I had a similar issue converting a date from RRDTool databases using rrdfetch but prefer one liners that I've been using since Apollo computer days.
Data looked like this:
localTemp rs1Temp rs2Temp thermostatMode
1547123400: 5.2788174937e+00 4.7788174937e+00 -8.7777777778e+00 2.0000000000e+00
1547123460: 5.1687014581e+00 4.7777777778e+00 -8.7777777778e+00 2.0000000000e+00
One liner:
rrdtool fetch -s -14400 thermostatDaily.rrd MAX | sed s/://g | awk '{print "echo ""\`date -r" $1,"\`" " " $2 }' | sh
Result:
Thu Jan 10 07:25:00 EST 2019 5.3373432378e+00
Thu Jan 10 07:26:00 EST 2019 5.2788174937e+00
On the face of it this doesn't look very efficient to me but this kind of methodology has always proven to be fairly low overhead under most circumstances even for very large files on very low power computer (like 25Mhz NeXT Machines). Yes Mhz.
Sed deletes the colon, awk is used to print the other various commands of interest including just echoing the awk variables and sh or bash executes the resulting string.
For methodology or large files or streams I just head the first few lines and gradually build up the one liner. Throw away code.

How can I generate Unix timestamps?

Related question is "Datetime To Unix timestamp", but this question is more general.
I need Unix timestamps to solve my last question. My interests are Python, Ruby and Haskell, but other approaches are welcome.
What is the easiest way to generate Unix timestamps?
In Linux or MacOS you can use:
date +%s
where
+%s, seconds since 1970-01-01 00:00:00 UTC. (GNU Coreutils 8.24 Date manual)
Example output now 1454000043.
in Ruby:
>> Time.now.to_i
=> 1248933648
curl icanhazepoch.com
Basically it's unix timestamps as a service (UTaaS)
In python add the following lines to get a time stamp:
>>> import time
>>> time.time()
1335906993.995389
>>> int(time.time())
1335906993
$ date +%s.%N
where (GNU Coreutils 8.24 Date manual)
+%s, seconds since 1970-01-01 00:00:00 UTC
+%N, nanoseconds (000000000..999999999) since epoch
Example output now 1454000043.704350695.
I noticed that BSD manual of date did not include precise explanation about the flag +%s.
In Bash 5 there's a new variable:
echo $EPOCHSECONDS
Or if you want higher precision (in microseconds):
echo $EPOCHREALTIME
In Perl:
>> time
=> 1335552733
The unix 'date' command is surprisingly versatile.
date -j -f "%a %b %d %T %Z %Y" "`date`" "+%s"
Takes the output of date, which will be in the format defined by -f, and then prints it out (-j says don't attempt to set the date) in the form +%s, seconds since epoch.
First of all, the Unix 'epoch' or zero-time is 1970-01-01 00:00:00Z (meaning midnight of 1st January 1970 in the Zulu or GMT or UTC time zone). A Unix time stamp is the number of seconds since that time - not accounting for leap seconds.
Generating the current time in Perl is rather easy:
perl -e 'print time, "\n"'
Generating the time corresponding to a given date/time value is rather less easy. Logically, you use the strptime() function from POSIX. However, the Perl POSIX::strptime module (which is separate from the POSIX module) has the signature:
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) =
POSIX::strptime("string", "Format");
The function mktime in the POSIX module has the signature:
mktime(sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
So, if you know the format of your data, you could write a variant on:
perl -MPOSIX -MPOSIX::strptime -e \
'print mktime(POSIX::strptime("2009-07-30 04:30", "%Y-%m-%d %H:%M")), "\n"'
in Haskell
import Data.Time.Clock.POSIX
main :: IO ()
main = print . floor =<< getPOSIXTime
in Go
import "time"
t := time.Unix()
in C
time(); // in time.h POSIX
// for Windows time.h
#define UNIXTIME(result) time_t localtime; time(&localtime); struct tm* utctime = gmtime(&localtime); result = mktime(utctime);
in Swift
NSDate().timeIntervalSince1970 // or Date().timeIntervalSince1970
For completeness, PHP:
php -r 'echo time();'
In BASH:
clitime=$(php -r 'echo time();')
echo $clitime
In Haskell...
To get it back as a POSIXTime type:
import Data.Time.Clock.POSIX
getPOSIXTime
As an integer:
import Data.Time.Clock.POSIX
round `fmap` getPOSIXTime
public static Int32 GetTimeStamp()
{
try
{
Int32 unixTimeStamp;
DateTime currentTime = DateTime.Now;
DateTime zuluTime = currentTime.ToUniversalTime();
DateTime unixEpoch = new DateTime(1970, 1, 1);
unixTimeStamp = (Int32)(zuluTime.Subtract(unixEpoch)).TotalSeconds;
return unixTimeStamp;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return 0;
}
}
Let's try JavaScript:
var t = Math.floor((new Date().getTime()) / 1000);
...or even nicer, the static approach:
var t = Math.floor(Date.now() / 1000);
In both cases I divide by 1000 to go from seconds to millis and I use Math.floor to only represent whole seconds that have passed (vs. rounding, which might round up to a whole second that hasn't passed yet).
If I want to print utc date time using date command I need to using -u argument with date command.
Example
date -u
Output
Fri Jun 14 09:00:42 UTC 2019
nawk:
$ nawk 'BEGIN{print srand()}'
Works even on old versions of Solaris and probably other UNIX systems, where '''date +%s''' isn't implemented
Doesn't work on Linux and other distros where the posix tools have been replaced with the GNU versions (nawk -> gawk etc.)
Pretty unintuitive but definitelly amusing :-)
For Unix-like environment the following will work.
# Current UNIXTIME
unixtime() {
datetime2unixtime "$(date -u +'%Y-%m-%d %H:%M:%S')"
}
# From DateTime(%Y-%m-%d %H:%M:%S)to UNIXTIME
datetime2unixtime() {
set -- "${1%% *}" "${1##* }"
set -- "${1%%-*}" "${1#*-}" "${2%%:*}" "${2#*:}"
set -- "$1" "${2%%-*}" "${2#*-}" "$3" "${4%%:*}" "${4#*:}"
set -- "$1" "${2#0}" "${3#0}" "${4#0}" "${5#0}" "${6#0}"
[ "$2" -lt 3 ] && set -- $(( $1-1 )) $(( $2+12 )) "$3" "$4" "$5" "$6"
set -- $(( (365*$1)+($1/4)-($1/100)+($1/400) )) "$2" "$3" "$4" "$5" "$6"
set -- "$1" $(( (306*($2+1)/10)-428 )) "$3" "$4" "$5" "$6"
set -- $(( ($1+$2+$3-719163)*86400+$4*3600+$5*60+$6 ))
echo "$1"
}
# From UNIXTIME to DateTime format(%Y-%m-%d %H:%M:%S)
unixtime2datetime() {
set -- $(( $1%86400 )) $(( $1/86400+719468 )) 146097 36524 1461
set -- "$1" "$2" $(( $2-(($2+2+3*$2/$3)/$5)+($2-$2/$3)/$4-(($2+1)/$3) ))
set -- "$1" "$2" $(( $3/365 ))
set -- "$#" $(( $2-( (365*$3)+($3/4)-($3/100)+($3/400) ) ))
set -- "$#" $(( ($4-($4+20)/50)/30 ))
set -- "$#" $(( 12*$3+$5+2 ))
set -- "$1" $(( $6/12 )) $(( $6%12+1 )) $(( $4-(30*$5+3*($5+4)/5-2)+1 ))
set -- "$2" "$3" "$4" $(( $1/3600 )) $(( $1%3600 ))
set -- "$1" "$2" "$3" "$4" $(( $5/60 )) $(( $5%60 ))
printf "%04d-%02d-%02d %02d:%02d:%02d\n" "$#"
}
# Examples
unixtime # => Current UNIXTIME
date +%s # Linux command
datetime2unixtime "2020-07-01 09:03:13" # => 1593594193
date -u +%s --date "2020-07-01 09:03:13" # Linux command
unixtime2datetime "1593594193" # => 2020-07-01 09:03:13
date -u --date #1593594193 +"%Y-%m-%d %H:%M:%S" # Linux command
https://tech.io/snippet/a3dWEQY
With NodeJS, just open a terminal and type: node -e "console.log(new Date().getTime())" or node -e "console.log(Date.now())"
In Rust:
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let now = SystemTime::now();
println!("{}", now.duration_since(UNIX_EPOCH).unwrap().as_secs())
}
If you need a Unix timestamp from a shell script (Bourne family: sh, ksh, bash, zsh, ...), this should work on any Unix machine as unlike the other suggestions (perl, haskell, ruby, python, GNU date), it is based on a POSIX standard command and feature.
PATH=`getconf PATH` awk 'BEGIN {srand();print srand()}'

Resources