bash shell script for last-week dates - shell

I am writing shell where I am going to need dates from last week irrespective of the day I am running on. I tried below but those are somehow failing. Can you please help.
date --date='last Monday'
date --date='last week + last Thursday'
date --date='last week + last Monday'
Thanks

Define on what day your week ends, and then work backwards from there. For example, assuming that your week ends on Sunday, then you can get all the dates from the previous week by doing:
saturday=$(date -d 'last Sunday - 1 day')
friday=$(date -d 'last Sunday - 2 days')
# etc.

Related

Unix shell scripting: date format syntax

I m trying to get yesterday date, it's not working in hp ux server.
Prev_date=$(date +"y%m%d" -d "1 day ago")
For this I m still getting current date only.
20210811
Could you please help on the same.
You missed a percentage in front of the 'y': this is working fine for me:
echo $(date +"%y%m%d" -d "1 day ago")
You can use below command, if you want.
date --date=' 1 days ago' '+%Y-%m-%d'
It will give result like
2021-09-06
I prefer this format since most of the time my scripts include SQL queries for data fetch and hence date is required to filter out data on daily basis.

Shell: How to calculate current MMYY to previous date (-15 months)

I am trying to calculate the current date MMYY - 15 months ago.
I get current date in the format I want with shell command: date +"%m%y"
I am trying to use this current date and calculate what the MMYY is 15 months ago, what command would show me this?
Not sure why you want to get the current MMYY and calculate "15 months ago" afterwards. You could just do it in one command:
date --date='15 months ago' +"%m%y"
man date and info date are your friend.

Why do I always get extra one day with date difference in bash?

I'm trying to calculate the seconds between a date from now, however, I always get extra one day when adding the seconds from now.
echo $(($(date -ud "2020-03-15 19:13" +'%s') - $(date +'%s')))
As of posting, the result is 1744204
Using this website to check, I gets 16 March, not 15 March as expected. Any idea why?
verify the result of your date commands and verify the timezone of both.
The first result of the command shows the timestamp in UTC, and the second one shows the timestamp using the timezone of the system.
Here is the difference:
$ date -ud "2020-03-15 19:13" +'%s'
1584299580
With UTC-3 in my system:
$ date -d "2020-03-15 19:13" +'%s'
1584310380
I hope that help you.

How to subtract a day from an invalid date in shell script?

I'm working on a script to automate the download of information from a customer in the period from 00:00 to 23:59 on the same day. To make the correct treatment of the first day of daylight saving time (10/15/2017, in my timezone - BRST), I need to check the timezone of the previous day. However, when I will subtract one day from the first valid time,
date --date="20171015 01:00 -1 day" +%Y-%m-%d
the result is the next day 2017-10-16, not the previous day 2017-10-14. Could anyone help me understand what I might be doing wrong and how should I do this operation in the right way?
I don't really trust GNU date's arithmetic. Instead, I would convert your starting time to seconds since the UNIX epoch, subtract 86400 seconds, and convert the result back to a day. Those conversion routines take daylight saving time into account.
$ TZ=BRST date +%s --date "20171015 01:00"
1508029200
$ TZ=BRST date +%F-%T --date #$((1508029200 - 86400))
2017-10-14-01:00:00
It appears the "BRST" timezone is not very useful: stick to Olson timezone names
$ TZ=BRST date --date="20171015 00:30" "+%F %T"
2017-10-15 00:30:00
$ TZ=America/Sao_Paulo date --date="20171015 00:30" "+%F %T"
date: invalid date ‘20171015 00:30’

How to schedule to run first Sunday of every month

I am using Bash on RedHat. I need to schedule a cron job to run at at 9:00 AM on first Sunday of every month. How can I do this?
You can put something like this in the crontab file:
00 09 * * 7 [ $(date +\%d) -le 07 ] && /run/your/script
The date +%d gives you the number of the current day, and then you can check if the day is less than or equal to 7. If it is, run your command.
If you run this script only on Sundays, it should mean that it runs only on the first Sunday of the month.
Remember that in the crontab file, the formatting options for the date command should be escaped.
It's worth noting that what looks like the most obvious approach to this problem does not work.
You might think that you could just write a crontab entry that specifies the day-of-week as 0 (for Sunday) and the day-of-month as 1-7, like this...
# This does NOT work.
0 9 1-7 * 0 /path/to/your/script
... but, due to an eccentricity of how Cron handles crontab lines with both a day-of-week and day-of-month specified, this won't work, and will in fact run on the 1st, 2nd, 3rd, 4th, 5th, 6th, and 7th of the month (regardless of what day of the week they are) and on every Sunday of the month.
This is why you see the recommendation of using a [ ... ] check with date to set up a rule like this - either specifying the day-of-week in the crontab and using [ and date to check that the day-of-month is <=7 before running the script, as shown in the accepted answer, or specifying the day-of-month range in the crontab and using [ and date to check the day-of-week before running, like this:
# This DOES work.
0 9 1-7 * * [ $(date +\%u) = 7 ] && /path/to/your/script
Some best practices to keep in mind if you'd like to ensure that your crontab line will work regardless of what OS you're using it on:
Use =, not ==, for the comparison. It's more portable, since not all shells use an implementation of [ that supports the == operator.
Use the %u specifier to date to get the day-of-week as a number, not the %a operator, because %a gives different results depending upon the locale date is being run in.
Just use date, not /bin/date or /usr/bin/date, since the date utility has different locations on different systems.
You need to combine two approaches:
a) Use cron to run a job every Sunday at 9:00am.
00 09 * * 7 /usr/local/bin/once_a_week
b) At the beginning of once_a_week, compute the date and extract the day of the month via shell, Python, C/C++, ... and test that is within 1 to 7, inclusive. If so, execute the real script; if not, exit silently.
A hacky solution: have your cron job run every Sunday, but have your script check the date as it starts, and exit immediately if the day of the month is > 7...
This also works with names of the weekdays:
0 0 1-7 * * [ "$(date '+\%a')" == "Sun" ] && /usr/local/bin/urscript.sh
But,
[ "$(date '+\%a')" == "Sun" ] && echo SUNDAY
will FAIL on comandline due to special treatment of "%" in crontab (also valid for https://stackoverflow.com/a/3242169/2919695)
Run a cron task 1st monday, 3rd tuesday, last sunday, anything..
http://xr09.github.io/cron-last-sunday/
Just put the run-if-today script in the path and use it with cron.
30 6 * * 6 root run-if-today 1 Sat && /root/myfirstsaturdaybackup.sh
The run-if-today script will only return 0 (bash value for True) if it's the right date.
EDIT:
Now with simpler interface, just one parameter for week number.
# run every first saturday
30 6 * * 6 root run-if-today 1 && /root/myfirstsaturdaybackup.sh
# run every last sunday
30 6 * * 7 root run-if-today L && /root/lastsunday.sh
There is a hacky way to do this with a classic (Vixie, Debian) cron:
0 9 1-7 * */7
The day-of-week field starts with a star (*), and so cron considers it "unrestricted" and uses the AND logic between the day-of-month and the day-of-week fields.
*/7 means "every 7 days starting from weekday 0 (Sunday)". Effectively, this means "every Sunday".
Here's my article with more details: Schedule Cronjob for the First Monday of Every Month, the Funky Way
Note – it's a hack. If you use this expression, make sure to document it to avoid confusion later.
maybe use cron.hourly to call another script. That script will then check to see if it's the first sunday of the month and 9am, and if so, run your program. Sounds optimal enough to me :-).
If you don't want cron to run your job everyday or every Sunday you could write a wrapper that will run your code, determine the next first Sunday, and schedule itself to run on that date.
Then schedule that wrapper for the next first Sunday of the month. After that it will handle everything itself.
The code would be something like (emphasis on something...no error checking done):
#! /bin/bash
#We run your code first
/path/to/your/code
#now we find the next day we want to run
nskip=28 #the number of days we want to check into the future
curr_month=`date +"%m"`
new_month=`date --date='$nskip days' +"%m"`
if [[ curr_month = new_month ]]
then
((nskip+=7))
fi
date=`date --date='$nskip days' +"09:00AM %D` #you may need to change the format if you use another scheduler
#schedule the job using "at"
at -m $date < /path/to/wrapper/code
The logic is simple to find the next first Sunday. Since we start on the first Sunday of the current month, adding 28 will either put us on the last Sunday of the current month or the first Sunday of the next month. If it is the current month, we increment to the next Sunday (which will be in the first week of the next month).
And I used "at". I don't know if that is cheating. The main idea though is finding the next first Sunday. You can substitute whatever scheduler you want after that, since you know the date and time you want to run the job (a different scheduler may need a different syntax for the date, though).
try the following
0 15 10 ? * 1#1
http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
00 09 1-7 * 0 /usr/local/bin/once_a_week
every sunday of first 7 days of the month

Resources