Subtract 20 month from user provided date in yymm in unix - shell

oldest_year_month_temp=201602
NUM_PART_RETAIN=20
oldest_year_month=`date --date="$(oldest_year_month_temp +%Y%m) - $NUM_PART_RETAIN month" "+%Y%m"`
Date is not coming as expected.

One easy way to do it would be to simply append a 01 to your input of yymm to provide a format date -d could read as the starting date, then simply subtract 20 months and output the resulting date in %y%m format. For example, if you provide the date 9910 (Oct. 1999), you can do:
$ date -d "991001 - 20 months" +%y%m
9802
Which returns Feb. 1998 (20 months earlier)
(note: the $ above just indicates a command by a normal user as opposed to # indicating a command by the super user (e.g. root))

Inside the $(...) there must be a command, e.g. $(date ...).
This should have been obvious from the error message you got, which was probably oldest_year_month_temp: no such command.
When reading from a variable, you must write a $ before its name.

Related

Why is the date command throwing an error despite successfully computing an answer?

For context I am working on a Windows machine with MINGW64. I have not had the chance to test this on a machine running Linux.
I am working with [date][1] in bash and trying to add days to a date represented as seconds since 1970-01-01 00:00:00, i.e. in format %s. I have the following Bash code:
DATE1=$(date --date=now "+%s")
echo "DATE1: ${DATE1}"
DATE2=$(date --date="$(date --date="${DATE1}" "+%s")+2 days" "+%d%b%Y %H:%M:%S")
echo "DATE2: ${DATE2}"
Which gives console output
DATE1: 156133763
date: invalid date '1561337963'
DATE2: 26Jun2019 10:59:24
In fact, DATE2 has the expected value down to the second. However the console still throws an error. Why might this error be occurring? Would it have something to do with running MINGW64?
An update:
I ran this on a Debian server I have access to. It computed the time with now like on MINGW, but returned a different error: ./test.sh: line 3: --date=1561342165: command not found.
Running this on the same server with a custom date:
DATE1=$(date --date="$(date --date="19Jun2019 11:35:46" "+%d%b%Y %H:%M:%S")" "+%s")
Likewise returns
DATE1: 1560908146
date: invalid date ‘1560908146’
DATE2: 26Jun2019 12:20:08
Which actually indicates it isn't adding to the defined date at all, rather it is just adding to today's date (it's the 24th of June where I am now). Clearly, something is quite wrong!
If you want to convert timestamp to a date then you have to use #:
date --date=#1561344591 '+%F %T'
2019-06-24 04:49:51
The reason why you got seemingly correct result even with the error message is because your DATE1 is now, so your inner date call produces an error and returns nothing and then the outer call is just --date=+2 days, which produces 2 days from now.
I don't think you can use date-time in timestamp format together with relative statements, it doesn't work even with #. You have to convert your timestamp to human readable date first but even then you have to be careful. You could think that this is enough:
date --date="$(date --date=#1561344591 "+%F %T") + 2 days" "+%F %T"
2019-06-25 04:49:51
As you can see it is still wrong and that's because +2 is parsed as a timezone. You fix it by explicitly including timezone in you conversion from timestamp:
date --date="$(date --date=#1561344591 "+%F %T%Z") + 2 days" "+%F %T"
2019-06-26 04:49:51
In general, using bash debugging set -x and date debugging date --debug ... helps with solving such problems.

Calculate 15 minutes ago in shell

I have a time-stamp like 7:00:00, which means 7am.
I would like to write a short command that returns 06:45:00, or simply 06:45, preferably using date command so that I can avoid long shell script. Do you have any elegant solution?
I'm also looking for a 24h format. For example, 12:00:00 - 15 minutes = 11:45:00.
With GNU date, use 7:00:00 AM - 15 minutes as d (--date) string :
% date -d '7:00:00 AM - 15 minutes' '+%H:%M'
06:45
+%H:%M sets the output format as HH:MM.
On BSD variants Date has a -v flag which can be used to take the current timestamp and display the result of a positive or negative adjustment.
This will subtract 15mins from the current timestamp:
date -v -15M

Deriving URLs from date

I would like to automate a download of an image from a third party server with a CRON job and then upload the image to my website.
I have 2 issues:
First, the third party site changes the image name every day using the following logic:
http://thirdpartysite.com/ImageFinder.aspx?ReportID=FILENAME
where FILENAME is 26601 +14 for each day after 6 Oct 2014 (so 7 Oct would be 26615, 8 Oct would be 26629 etc).
How do I build this into a simple Linux bash script for use with wget?
Second, how do I upload this to my site via FTP (or similar) with the same script.
NOTE: I have permission to host the file on my site and have linked the original site / placed credit for the image.
Following the suggestions of #Abhay, first get the timestamp of Oct 6, let's store it in the variable $d0:
d0=$(date +%s -d 20141006)
Then store the timestamp of a target date, say Oct 8 and store it in $d1:
d1=$(date +%s -d 20141008)
Then you can calculate the difference and apply the required arithmetic operations in $((...)), like this:
echo $((26601 + 14 * (d1 - d0) / 60 / 60 / 24))
# outputs: 26629
The date command has one very good format: %s, which prints number of seconds since "epoch", which is the fixed date 1 January 1970, 00:00 UTC. I'll call it "timestamp". In combination with this, you can use the -d date-string, so that it prints the given date as number of seconds. Now you can take today's timestamp, subtract the timestamp of "6 Oct 2014" from it, and you get number of seconds between the two times. Now you can divide it by (60 * 60 * 24) to get it in number of days, and do further arithmetic to get the desired number, and make a file name out of it.
The date string formats that -d option takes are flexible, but as of now I am not sure whether it takes "6 Oct 2014" as is. Try a few permutations, or better, check the "info" page.

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.

Resources