How subtract days from date in bash shell on Solaris 11? - bash

I've been trying subtrac some days $days from a date $date with format yyyy-MM-dd, but nothing has worked on Solaris 11. Some solution is a 'trick' with the timezone, but it depends on the timezone and I think that is exactly that, a trick.
I would like a cheaper solution, because the only thing I can think is to convert the date to julian representation and then subtract one day and again obtain yyyy-MM-dd representation, for example:
date=2000-12-31
days=1
julian=$(toJulian $date)
resultJulian=$(subtractDays $julian $days)
resultGregorian=toGregorian $resultJulian
So, how can I do it without all this proccess? Thanks.

If you don't have GNU date or GNU awk, consider perl:
subtractDays() {
local date numDays
date=$1
numDays=$2
date=$date days=$numDays perl -e '
use Env qw(date days);
use Time::Piece;
use Time::Seconds;
my $start_time = Time::Piece->strptime($date, "%Y-%m-%d");
my $end_time = $start_time - (ONE_DAY * $days);
print $end_time->ymd . "\n";'
}
...thereafter:
subtractDays 2000-12-31 1
...emits...
2000-12-30

Here's the solution for Solaris 11:
#!/bin/bash
mydate="2016-08-01"
days=3
date_in_the_past=$(gdate -d "${mydate} - ${days} days")
You may wonder why I use gdate when you say it is not available?
Well, GNU Date is in fact available by default on a Solaris 11 install. It is accessed by the gdate command (full path is /usr/bin/gdate).
Some background: GNU Date is part of "GNU Coreutils" package and this package gets installed on any Solaris 11 server unless your customer has actively selected to exclude it. I doubt that is the case.
So gdate is there somewhere, but you say you can't find it? The reason is probably that you are in a local zone, not the global zone. This particular package doesn't get propagated by default into local zones when they are created. This is done in a (misguided, if you ask me) effort to save disk space. This difference between global zones and local zones is somewhat unknown to many Solaris admins.
When you explain to Solaris admins that in fact the binary already physically reside on the disk then it suddenly becomes more acceptable for them to execute the command required:
from the local zone:
pkg install file/gnu-coreutils
The above command doesn't actually go outside the server. It doesn't fetch the package from a remote package repository. The command will work even if you execute it when the server is detached from any network because the package is already there on the disk. Once you explain that to your Solaris admin he's typically okay with executing the command.

Related

How to get last Week's date in bash SunOS

Here is my issue: I have a backup bash script that needs to access a folder with a date in its name for example : backup_01072022 .
I used date=`TZ=GMT+24 date +%d%m%Y` when i needed to access the backup folder of yesterday.
Now I want to access the backup folder of last week :
date=`TZ=GMT+168 date +%d%m%Y` , it doesn't work , it show today's date.
I read that TZ doesn't work for a value above +144.
Is there any other way of manipulating dates in SunOS 6.8 ?
Notes :
SunOS 6.8
version of the date util : 8.5
version of bash : 4.1.11(2)-release
This'll depend on the version of date on your system.
With GNU date (v 8.26):
$ TZ=GMT date '+%d%m%Y'
06072022 # today
$ TZ=GMT date '+%d%m%Y' -d 'last week'
29062022
$ TZ=GMT date '+%d%m%Y' -d '7 days ago'
29062022
NOTE: I'll leave it up to OP to determine if the explicit TZ setting should be adjusted (or used at all)
I seem to recall SunOS comes with Perl, so if you don't have a date that supports --date="...", you should be able to do:
date=$(perl -MPOSIX -e '
print POSIX::strftime "%d%m%Y", localtime time-(60*60*24*7)
')
Thanks to the helpful commments and answers I was able to make it work using :
/usr/gnu/bin/date -d "last week" '+%d%m%Y'
It turns out I was not using the GNU date util until I specified it explicitly, and that's neither --date nor -d was working for me.
I still can't figure out what date util I was using by default if not GNU date.

FreeBSD script to show active connections and append number remote file

I am using NetScaler FreeBSD, which recognizes many of the UNIX like commands, grep, awk, crontab… etc.
I run the following command to get the number of connected users that we have on the system
#> nsconmsg -g aaa_cur_ica_conn -d stats
OUTPUT (numbered lines):
Line1: Displaying current counter value information
Line2: NetScaler V20 Performance Data
Line3: NetScaler NS11.1: Build 63.9.nc, Date: Oct 11 2019, 06:17:35
Line4:
Line5: reltime:mili second between two records Sun Jun 28 23:12:15 2020
Line6: Index reltime counter-value symbol-name&device-no
Line7: 1 2675410 605 aaa_cur_ica_conn
…
…
From above output - I only need the number of connected users (represented in Line 7, 3rd column (605 to be precise), along with the Hostname and Time (of the running script)
Now, to extract this important 3rd column number i.e. 605, along with the hostname, and time of data collected - I wrote the following script:
printf '%s - %s - %s\n' "$(hostname)" "$(date '+%H:%M')" "$(nsconmsg -g aaa_cur_ica_conn -d stats | grep aaa_cur_ica_conn | awk '{print $3}')"
The result is perfect, showing hostname, time, and the number of connected users as follows:
Hostname - 09:00 – 605
Now can anyone please shed light on how I can:
Run this script every day - 5am to 5pm (12hours)?
Each time scripts runs - append a file on a remote Unix share with the output?
I appreciate this might be a bit if a challenge... however would be grateful for any bash scripts wizards out there that can create magic!
Thanks in advance!
I would suggest a quick look into the FreeBSD Handbook or For People New to Both FreeBSD and UNIX® so that you could get familiar with the operating system and tools that could help you achieve better what you want.
For example, there is a utility/command named cron
The software utility cron is a time-based job scheduler in Unix-like computer operating systems.
For example, to run something all days between 5am to 5pm every minute, you could use something like:
* 05-17 * * * command
Try more options here: https://crontab.guru/#*_05-17_*_*_*.
There are more tools for scheduling commands, for example at (https://en.wikipedia.org/wiki/At_(command)) but this something you need to evaluate and read more about it.
Now regarding the command, you are using to get the "number of connected users", you could avoid the grep and just used awk for example:
awk '/aaa_cur_ica_conn/ {print $3}'
This will print only column 3 if line contains aaa_cur_ica_conn, but as before I invite you to read more about the topic so that you could bet a better overview and better understand the commands.
Last but not least, check this link How do I ask a good question? the better you could format, and elaborate your question the easy for others to give an answer.

Bash scripting: date -d won't accept my string format of hhmmss. I need a workaround

I need a Bash script to accept 1 argument representing a time in hhmmss format, and from that derive a second time 3 minutes before that.
I've been trying to use date -d:
#! /bin/bash
DATE=`date +%Y%m%d`
TIME=$1
NEWTIME=`date -d "$DATE $TIME - 3 minutes" +%H%M%S`
echo $NEWTIME
In action:
$ ./myscript.sh 123456
invalid date `20141022 123456 - 3 minutes'
It seems the problem is with the 6 character time format because 4 characters (eg 1234) works. The subtraction of the 3 minutes is not the problem because I get the same error when I remove it.
It has occurred to me I could parse the time into a more palatable format before sending it to date. I tried inserting delimiters by adding this line:
TIME=${TIME:0:2}:${TIME:2:2}:${TIME:4:2}
It accepted that format but the answer to the - 3 minutes part was inexplicably very wrong (it subtracted 2 hours and 1 minute):
$ ./myscript.sh 123456
103356
Vexing.
It has also occurred to me that I might be able to provide date with an input format, like strptime which I'm familiar with from Python. I've found references to strptime in the context of Bash but I've been unable to get it to do anything.
Does anyone have any suggestions on getting the hhmmss time-string to work? Any help is much appreciated.
FYI: I'm trying to avoid changing the 6 character input format because that would involve changing other scripts as well as getting certain human users to alter long-entrenched habits. I'm also trying to avoid outsourcing this task to another language. (I could easily do this in Python). I want a Bash solution to this problem, if there is one.
TIME=093000
TIME=${TIME:0:2}:${TIME:2:2}:${TIME:4:2} # your line
date -d "2014-10-20 $TIME 3 mins ago" +%H%M%S
Output:
092700

Text-Message Gateways & Incrementing Bash Variable Daily

I have a bash script that is sending me a text daily, for 100 days.
#! /bin/bash
EMAIL="my-phone-gateway#address.net"
MESSAGE="message_content.txt"
mail $EMAIL < $MESSAGE
Using crontab, I can have the static $MESSAGE sent to me every day.
Other than hard-coding 100 days of texts ;)
How could I implement a variable counter such that I can have my texts say:
"Today is Day #1" on the first day, "Today is Day #2" on the second day, etc. ?
Note: The location of the requested text within the $MESSAGE file doesn't matter. Last line, first line, middle, etc.
The only requirement for an answer here is that I know what day it is relative to the first, where the first day is the day the script was started.
Of course, bonus awesome points for the cleanest, simplest, shortest solution :)
For our nightly build systems, I wrote a C program that does the calculation (using local proprietary libraries that store dates as a number of days since a reference date). Basically, given a (non-changing) reference date, it reports the number of days since the reference date. So, the cron script would have a hard-wired first day in it, and the program would report the number of days since then.
The big advantage of this system is that the reference date doesn't change (very often), so the script doesn't change (very often), and there are no external files to store information in.
There probably are ways to achieve the same effect with standard Unix tools, but I've not sat down and worked out the portable solution. I'd probably think it terms of using Perl. (The C program only works up to 2999 CE; I left a note in the code for people to contact me about 50 years before it becomes a problem for the Y3K fix. It is probably trivial.)
You could perhaps work in terms of Unix timestamps...
Create a script 'days_since 1234567890' which treats the number as the reference date, gets the current time stamp (from date with appropriate format specification; on Linux, date '+%s' would do that job, and it works on Mac OS X too), takes the difference and divides by 86,400 (the number of seconds in a day).
refdate=1234567890
bc <<EOF
scale=0
($(date '+%s') - $refdate) / 86400
EOF
An example:
$ timestamp 1234567890
1234567890 = Fri Feb 13 15:31:30 2009
$ timestamp
1330027280 = Thu Feb 23 12:01:20 2012
$ refdate=1234567890
$ bc <<EOF
> scale=0
> ($(date '+%s') - $refdate) / 86400
> EOF
1104
$
So, if the reference date was 13th Feb 2009, today is day 1104. (The program bc is the calculator; its name has nothing to do with Anno Domini or Before Christ. The program timestamp is another homebrew of mine that prints timestamps according to a format that can be specified; it is a specialized variant of date originally written in the days before date had the functionality, by which I mean in the early 1980s.)
In a Perl one-liner (assuming you specify the reference date in your script):
perl -e 'printf "%d\n", int((time - 1234567890)/ 86400)'
or:
days=$(perl -e 'printf "%d\n", int((time - 1234567890)/ 86400)')
The only way to accomplish this would be to store the date in a file, and read from that file each day. I would suggest storing the epoch time.
today=$(date +%s)
time_file="~/.first_time"
if [[ -f $time_file ]]; then
f_time=$(< "$time_file")
else
f_time=$today
echo "$f_time" > "$time_file"
fi
printf 'This is day: %s\n' "$((($today - $f_time) / 60 / 60 / 24))"
Considering that your script is running only once a day, something like this should work:
#!/bin/bash
EMAIL="my-phone-gateway#address.net"
MESSAGE="message_content.txt"
STFILE=/tmp/start.txt
start=0
[ -f $STFILE ] && start=$(<$STFILE)
start=$((start+1))
MESSAGE=${MESSAGE}$'\n'"Today is Day #${start}"
echo "$start" > $STFILE
mail $EMAIL < $MESSAGE
A simple answer would be to export the current value to an external file, and read that back in again later.
So, for example, make a file called "CurrentDay.dat" that has the number 1 in it.
Then, in your bash script, read in the number and increment it.
e.g. your bash script could be:
#!/bin/bash
#Your stuff here.
DayCounter=$(<CurrentDay.dat)
#Use the value of DayCounter (i.e. $DayCounter) in your message.
DayCounter=$((DayCounter + 1))
echo $DayCounter > CurrentDay.dat
Of course, you may need to implement some additional checks to avoid something going wrong, but that should work as is.

Subtracting time from file creation/modification date in OSX

I am trying to shift the dates of a series of files by 9 hours. I've reached as far as this:
for i in *.MOV; do touch -r "$i" -d "-9 hours" "$i"; done
This should work in recent systems, but the touch command in OSX seems to be a bit outdated and not to support the -d switch.
I'm using Snow Leopard. Any idea on the best option for doing this with a single line command? I don't want to create a script for this.
Ok, sorted it out. OSX comes with a gtouch command, that knows the -d switch. It's part of GNU coreutils. See the comments below for information regarding availability on specific MacOS versions.
For more information on using relative dates with the -d switch see the manual.
Looking at the Wikipedia Page for Touch, it appears you're accustomed to the GNU version of Touch. Which MacOS isn't using.
For what you want to do, look into the "SetFile" command, which gets installed with XCode tools. You have -d and -m options, which reset the Created and Modified dates & times respectively.
http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/SetFile.1.html
Donno OS X, but it should be easy enough to
get curr time stamp on the file
convert it to seconds
subtract 9 hours (9*60*60 secs) from it
convert it back to the format accepted by touch's -t option
run touch command
All this of course can be done in a single for loop on command line.
Here are simple examples from WikiPedia showing back and forth conversion.
# To convert a specific time stamp to Unix epoch time (seconds since 1970-01-01):
date +"%s" -d "Fri Apr 24 13:14:39 CDT 2009"
# 1240596879
# To convert Unix epoch time (seconds since 1970-01-01) to a human readable format:
date -d "UTC 1970-01-01 1240596879 secs"
# Fri Apr 24 13:14:39 CDT 2009
# Or:
date -ud #1000000000
# Sun Sep 9 01:46:40 UTC 2001
# or: Haven't tested this but should work..
date -d #1000000000 +%y%m%d%%H%M%S
# 010909014640

Resources