shell script for date between 2 different dates - bash

I'm struggling a bit on how to put the correct date in my shell script for a specific time range.
For instance i need to check if i'm in the correct range to generate some file based on date(12am - 3am )
so far I'm checking :
workflow_start_time=$(date -d "$(date +%Y-%m-%d) 23:00:00" +"%s")
scheduled_run_time=$workflow_start_time
if [ "$(date -d #${scheduled_run_time} +"%H")" -ge 23 ] && [ "$(date -d #${scheduled_run_time} +"%H")" -lt 2 ]; then
that is starting at 23 because i need to take into account 1 hour server difference, so this will start around 12 and should finish around 2am, which will be 3am.
any help here?

Convert date to timestamp.
toStamp() { date --date="$1" +%s; }
Check if date is between other dates.
# [$1, $2): bounds
# $3 current date
isBetween() {
[[ `toStamp $1` -le `toStamp $3` ]]&&\
[[ `toStamp $2` -gt `toStamp $3` ]]
}
or
isTimeStampBetween() {
[[ $1 -le $3 ]]&&\
[[ $2 -gt $3 ]]
}
if you have timestamps only.
An example to check if a date is between 2 other would be:
if $(isBetween 2012 2020 2013) ; then dosomething
You can include these functions in your file.

Related

bash automate the user input <enter> in the loop

#!/bin/sh
dom=$(date '+%d') # 01-31, day of month
year=$(date '+%Y') # four-digit year
month=$(date '+%m') # two-digit month
nworkdays=0
for d in $( seq 1 $dom)
do
today=$(date -d "$year-$month-$d" '+%x') # locale's date representation (e.g. 12/31/99)
dow=$(date -d "$year-$month-$d" '+%u') # day of week: 1-7 with 1=Monday, 7=Sunday
if [ "$dow" -le 5 ] && grep -vq "$today"
then
workday=Yes
nworkdays=$((nworkdays+1))
else
workday=
fi
done
[ "$workday" ] && [ "$nworkdays" -eq 6 ] && echo "$nworkdays $today $workday"
~
I wanted to execute the script but the script goes inside the loop and asks for user input.
Expected result
on execution display workday
Best Regards,
Shalini
As mentioned by #urbanespacemen kindly remove the grep command
#!/bin/sh
dom=$(date '+%d') # 01-31, day of month
year=$(date '+%Y') # four-digit year
month=$(date '+%m') # two-digit month
nworkdays=0
for d in $( seq 1 $dom)
do
today=$(date -d "$year-$month-$d" '+%x') # locale's date representation (e.g. 12/31/99)
dow=$(date -d "$year-$month-$d" '+%u') # day of week: 1-7 with 1=Monday, 7=Sunday
if [ "$dow" -le 5 ]
then
workday=Yes
nworkdays=$((nworkdays+1))
else
workday=
fi
done
[ "$workday" ] && [ "$nworkdays" -eq 6 ] && echo "$nworkdays $today $workday"
Now should work

Bash: start date less than equal to end date

#!/bin/bash
# slightly malformed input data
input_start=2014-11-1
input_end=2016-01-1
# After this, startdate and enddate will be valid ISO 8601 dates,
# or the script will have aborted when it encountered unparseable data
# such as input_end=abcd
startdate=$(date -I -d "$input_start") || exit -1
enddate=$(date -I -d "$input_end") || exit -1
m="$startdate"
while [ "$m" != "$enddate" ]; do
echo $m
m=$(date -I -d "$m + 1 month")
done
"Script is running fine but when I want to change the While loop condition i.e '<=' 'less then or equal to' its giving error even I tried using "-le".What I want to do here is startdate <= enddate in while loop. Can anyone suggest what needs to done to overcome this issue.
Same Code
-le is for numeric data. 2014-11-01 is not a number. Use < or >. (You need to escape them as \< or \>. Or use [[ instead of [.)
effectively, change
while [ "$m" != "$enddate" ]; do
to
until [ "$m" \> "$enddate" ]; do
or
until [ "$m" '>' "$enddate" ]; do
or
until [[ "$m" > "$enddate" ]]; do
Alternately, use seconds since epoch instead of ISO8601 format.
while [ "$(date -d "$m" +%s)" -le "$(date -d "$enddate" +%s)" ]; do
With dateutils' datetest this is simple:
$ datetest 2014-11-1 --le 2016-01-1 ; echo $?
0
$ datetest 2014-11-1 --gt 2016-01-1 ; echo $?
1
Then again, what you want is simply done by dateseq, which also happens to be a tool of the dateutils suite.
$ dateseq 2014-11-1 +1mo 2016-01-1
2014-11-01
2014-12-01
2015-01-01
2015-02-01
2015-03-01
2015-04-01
2015-05-01
2015-06-01
2015-07-01
2015-08-01
2015-09-01
2015-10-01
2015-11-01
2015-12-01
2016-01-01
Disclaimer: I am the author of the package.

Bash Script for deleting old backup files

every night my server creates backups for every mysql database. All of these files are saved in a folder like /backup/mysql/2014-11-28. Over the last few months a lot of folders and files have been stored in that directory and I would like to reduce this.
Therefore I would need a bash script which deletes every folder in the given directory, except every folder created this month (not in the last 30 days, but the actual month) and except one backup from every week (for example the backup from sunday). Since I have no clue how to do the sunday party I decided it would be simpler to keep the backups from the 07th, the 14th, the 21st and the the 28th.
#!/bin/bash
in_array() {
local haystack=${1}[#]
local needle=${2}
for i in ${!haystack}; do
if [[ ${i} == ${needle} ]]; then
return 0
fi
done
return 1
}
YEAR=`date +%Y`
LASTYEAR=`date +%Y -d "1 year ago"`
MONTH=`date +%m`
DAYS="07 14 21 28"
for i in $( ls ); do
BACKUP_YEAR=$(echo "${i}" | cut -d'-' -f1)
BACKUP_MONTH=$(echo "${i}" | cut -d'-' -f2)
BACKUP_DAY=$(echo "${i}" | cut -d'-' -f3)
DELETE=false
if [[ "$BACKUP_YEAR" == "$YEAR" ]]; then
if [[ "$BACKUP_MONTH" != "$MONTH" ]]; then
if [ $(in_array $DAYS "$BACKUP_DAY") ]; then
DELETE=true
fi
fi
fi
if [[ "$BACKUP_YEAR" == "$LASTYEAR" ]]; then
if [[ "$BACKUP_DAY" != ${DAYS[0]} ]]; then
DELETE=true
fi
fi
if [ "$DELETE" = true ] ; then
#OUTPUT=`rm -v -R $i`
echo $i
fi
done
The second part (backups from the year before) works perfectly fine, but the first part (for backups from this year) doesn't work and I don't know why. I found the function on this site, but I guess somehow my call is wrong.
EDIT: The code I am now using:
#!/bin/bash
read YEAR MONTH <<<$(date "+%Y %m")
LASTYEAR=$(( YEAR-1 ))
DAYS=" 07 14 21 28 "
for fn in $( ls )
do
if ([ "${fn:0:4}" = "$YEAR" ] &&
[ "${fn:5:2}" != "$MONTH" ] &&
[ "${DAYS/ ${fn:8:2} /}" = "$DAYS" ]) || ([ "${fn:0:4}" = "$LASTYEAR" ] &&
[ "${fn:8:2}" != ${DAYS:1:2} ])
then
#OUTPUT=`rm -v -R $fn`
echo "$fn"
fi
done
#!/bin/bash
read YEAR MONTH <<<$(date "+%Y %m")
LASTYEAR=$(( YEAR-1 ))
DAYS=" 07 14 21 28 "
for fn in $( ls )
do
DELETE=false
if [ "${fn:0:7}" = "$YEAR-$MONTH" ] &&
[ "${DAYS/ ${fn:8:2} /}" != "$DAYS" ]
then
DELETE=true
elif [ "${fn:0:4}" = "$LASTYEAR" ] &&
[ "${fn:8:2}" != ${DAYS:1:2} ]
then
DELETE=true
fi
if [ "$DELETE" = true ]
then
#OUTPUT=`rm -v -R $fn`
echo "$fn"
fi
done
Assuming that a file name matches the following date format YYYY-MM-DD, for instance, 2014-03-27, the expression ${fn:0:7} would be 2014-03; ${fn:8:2} would be 27; ${fn:0:4} would be 2014.
Read the bash manual pages about the parameter expansion.
The expression ${DAYS/ ${fn:8:2} /} checks the day from the filename (wrapped by white spaces) is found in the DAYS list. It would be equivalent to echo "${DAYS}" | grep -q "${BACKUP_DAY}".
note: it is possible to reduce the commands inside the for loop (join if and elif by means of a || and remove the DELETE variable checking and the DELETE variable itself) but I decided to keep the look of the original script.

How to use korn shell get the first/last day of previous month

my ksh version is not allowed date -d.
The bellow code has problem when current month is January.
#!/bin/ksh
yy=`date +%Y`
mm=`date +%m-1|bc`
[ $mm -lt 1 ] && (mm=12;yy=`expr $yy - 1`)
[ $mm -le 9 ] && mm="0$mm"
getcal=`cal $mm $yy`
last_dd=`echo $getcal|awk '{print $NF}'`
dd1=`echo $getcal|awk '{print $10}'`
first_dd="0$dd1"
echo $yy$mm$last_day
echo $yy$mm$first_day
You're using a subshell: any variable changes you make will not survive the subshell exiting:
$ m=5; (m=10); echo $m
5
Use a different grouping construct
[ $mm -lt 1 ] && { mm=12; ((yy -= 1)); }
If you have GNU date, you can do:
$ first_of_this_month=$(date "+%Y-%m-01")
$ date -d "$first_of_this_month - 1 day" "+%Y-%m-%d"
2014-03-31
$ date -d "$first_of_this_month - 1 month" "+%Y-%m-%d"
2014-03-01

bash shell script for yesterdays date (last working day)

I am writing a bash script that needs to print the date of the last working day. So for example if the script is run on a Monday, it will print the date for last Friday.
I found that this prints yesterdays date:
date -d '1 day ago' +'%Y/%m/%d'
I also know that I can get the day of the week by using this statement
date +%w
I want to combine these two statements in order to have a little helper script that prints the required date. The logic goes something like this (note: its Pseudo code - I've never written a bash script)
DAY_OF_WEEK = `date +%w`
if (%DAY_OF_WEEK == 1)
LOOK_BACK = 3
elif
LOOK_BACK = 1
fi
echo `date -d '%LOOK_BACK day ago' +'%Y/%m/%d'`
Can someone help by correcting the pseudo code above?
(I am running on Ubuntu 10.0.4)
You were so close:
day_or_week=`date +%w`
if [ $day_or_week == 1 ] ; then
look_back=3
else
look_back=1
fi
date -d "$look_back day ago" +'%Y/%m/%d'
Sunday also needs to be checked.
DAY_OF_WEEK=`date +%w`
if [ $DAY_OF_WEEK = 0 ] ; then
LOOK_BACK=2
elif [ $DAY_OF_WEEK = 1 ] ; then
LOOK_BACK=3
else
LOOK_BACK=1
fi
date -d "$LOOK_BACK day ago" +'%Y/%m/%d'
I'm using a Mac, so my date command doesn't have the same -d flag yours seems to, but the following should work if it behaves as you've indicated:
if [[ $(date +%w) == 1 ]]
then
LOOK_BACK=3
else
LOOK_BACK=1
fi
date -d "${LOOK_BACK} day ago" +%Y/%m/%d
For OSX (tested on 10.9.2 and 10.13.4), so probably any environment where you are using BSD date.
if [ $(date +%w) == 1 ] ; then
date -v-3d +'%Y/%m/%d'
else
date -v-1d +'%Y/%m/%d'
fi
You can check to see if you are using BSD date by
$ man date | grep "BSD General"
Putting the other answers together, I came up with this:
last_workday() {
from_date="${#:-today}"
day_of_week=$(date +%w --date="${from_date}")
if [ ${day_of_week} = "0" ] ; then
look_back=2
elif [ ${day_of_week} = "1" ] ; then
look_back=3
else
look_back=1
fi
date -d "${from_date} - ${look_back} day" +'%Y/%m/%d'
}
next_workday() {
from_date="${#:-today}"
day_of_week=$(date +%w --date="${from_date}")
if [ ${day_of_week} = "5" ] ; then
look_forward=3
elif [ ${day_of_week} = "6" ] ; then
look_forward=2
else
look_back=1
fi
date -d "${from_date} + ${look_forward} day" +'%Y/%m/%d'
}
for i in $(seq 16); do
now=$(date +'%Y/%m/%d' --date="today + ${i} day")
prev=$(last_workday "${now}")
next=$(next_workday "${now}")
echo "${now}: ${prev} ${next}"
done
A more concise form using a bash inline "ternary" expression:
[[ $(date +%w) == 1 ]] && days=3 || days=1
date -d "$days day ago" +"%Y-%m-%d"

Resources