I'm trying to the month number of the last Monday of this week. I got it to check what day of the week it is and if it's not Monday then subtract x days and set that new date as the variable value.
What I'm having trouble with is formatting this variable to only get the month. Everything works except the 2nd to last line below.
startDate=$(date)
weekDayNum=$(date +'%u') # 1 is Monday
# If today is NOT Monday
if [ weekDayNum > 1 ];
then
# Get the date for the last Monday
newWeekDayNum=$(($weekDayNum-1))
startDate=$(date -j -v-${newWeekDayNum}d)
fi
month=$(date -d "$startDate" +'%m')
echo $month```
[ weekDayNum > 1 ] doesn't test for numeric order. Use [ $weekDayNum -gt 10 ] (you also did not access the value of your weekDayNum variable).
It seems you have to supply the format string in the BSD variant of date:
This works for me:
#!/usr/bin/env bash
LANG=C
startDate=$(date)
weekDayNum=$(date +'%u') # 1 is Monday
# If today is NOT Monday
if [ $weekDayNum -gt 1 ];
then
startDate=$(date -j -v "-$(($weekDayNum - 1))d")
fi
month=$(date -j -f "%a %b %d %T %Z %Y" "${startDate}" +'%m')
echo $month
Use expr to convert it to number.
month=$(date -d "$startDate" +'%m')
month=$(expr $month + 0)
echo $month
Output:
8
Related
I want to write a bash script that determines the 10 day period (decade) has ended relative to the start date (in the format YYYY-MM-DD).
If the 10 day period is finished script has to output the 10 days period.
Im new in bash and has a lot syntax errors with code, help me pls.
#!/bin/bash
# GNU bash, version 4.3.46
CURRENT_DATE=$(date +%Y-%m-%d)
START_DATE=2019-01-01
IS_TODAY_DECADE_CALCULATION_DAY = (CURRENT_DATE - START_DATE) % 10
if [ $IS_TODAY_DECADE_CALCULATION_DAY -eq 0 ]
then
BEGIN_DATE = $("$CURRENT_DATE - 11 days" +%Y-%m-%d)"
END_DATE = $("$CURRENT_DATE - 1 day" +%Y-%m-%d)"
echo "Period is="$BEGIN_DATE":"$END_DATE"
else
echo "Decade is not finished."
fi
You should compare the unix time stamps. If the time stamp "now+10 days" is larger than the start date, the period is ended.
#! /bin/bash
DATE_OLD=$(date "+%F" -d "-11 days")
DATE_NOW=$(date "+%F")
TEST_DATE_NOW=$(date "+%s" -d ${DATE_NOW})
TEST_DATE_OLD=$(date "+%s" -d ${DATE_OLD})
DIVIDER=$(( (TEST_DATE_NOW - TEST_DATE_OLD) / (60*60*24) ))
REMAINING=$(( DIVIDER % 10 ))
echo "Days between ${DATE_OLD} and ${DATE_NOW} is $DIVIDER"
if [ ${DIVIDER} -gt 0 ]; then
echo "Date ${DATE_OLD} is in the past"
else
echo "Date ${DATE_OLD} is in the future"
fi
if [ $REMAINING -eq 0 ]; then
echo "Ten days period ended"
else
echo "Still in ten day period"
fi
exit 0;
The question implies that the code should identify each 10 day period starting on a specific START_DATE. Bash does not have date math - it can not calculate difference between dates (as expected by '(CURRENT_DATE - START_DATE)'). Two options
Convert date to seconds since Unix Epoch, and do the math on those values, OR
Use date utilities package, OR
using Python, awk, perl
Implementing #1 is simple. Notice few changes to assignments - in particular no spaces are allowed in assignments variable=expression, or let variable=expression
#! /bin/bash
CURRENT_DATE=$(date +%Y-%m-%d)
START_DATE=2019-01-01
# Instead of IS_TODAY_DECADE_CALCULATION_DAY = (CURRENT_DATE - START_DATE) % 10
SEC_IN_DAY=$((60*60*24))
let D1=$(date '+%s' -d "$CURRENT_DATE Z")/SEC_IN_DAY
let D2=$(date '+%s' -d "$START_DATE Z")/SEC_IN_DAY
let IS_TODAY_DECADE_CALCULATION_DAY=(CURRENT_DATE-START_DATE)%10
# Rest of script here
if [ $IS_TODAY_DECADE_CALCULATION_DAY -eq 0 ]
then
BEGIN_DATE=$(date -d "$CURRENT_DATE - 11 days" +%Y-%m-%d)
END_DATE=$(date -d "$CURRENT_DATE - 1 day" +%Y-%m-%d)
echo "Period is=$BEGIN_DATE:$END_DATE"
else
echo "Decade is not finished."
fi
In bash on macOS, I would like to write a small script with dates (or any other program that would do) that gives me a list of dates in the format yyyymmdd of every Saturday of a given year and saves it to a variable.
For example, if I wanted to have a list of dates for all Saturdays of the year 1850, it should somehow look like this:
var = [ 18500105, 18500112, 18500119, …, 18501228 ]
with the below code:
list=()
for month in `seq -w 1 12`; do
for day in `seq -w 1 31`; do
list=( $(gdate -d "1850$month$day" '+%A %Y%m%d' | grep 'Saturday' | egrep -o '[[:digit:]]{4}[[:digit:]]{2}[[:digit:]]{2}' | tee /dev/tty) )
done
done
However, the above command does not write anything in the array list although it gives me the right output with tee.
How can I fix these issues?
Modifying Dennis Williamson's answer slightly to suit your requirement and to add the results into the array. Works on the GNU date and not on FreeBSD's version.
#!/usr/bin/env bash
y=1850
for d in {0..6}
do
# Identify the first day of the year that is a Saturday and break out of
# the loop
if (( $(date -d "$y-1-1 + $d day" '+%u') == 6))
then
break
fi
done
array=()
# Loop until the last day of the year, increment 7 days at a
# time and append the results to the array
for ((w = d; w <= $(date -d "$y-12-31" '+%j'); w += 7))
do
array+=( $(date -d "$y-1-1 + $w day" '+%Y%m%d') )
done
Now you can just print the results as
printf '%s\n' "${array[#]}"
To set up the GNU date on MacOS you need to do brew install coreutils and access the command as gdate to distinguish it from the native version provided.
Argh, just realised you need it for MacOS date.
I will leave the answer for others that do not have that restriction, but it will not work for you.
This is not quite what you want, but close:
year=1850
firstsat=$(date -d $year-01-01-$(date -d $year-01-01 +%w)days+6days +%Y%m%d)
parset a 'date -d '$firstsat'+{=$_*=7=}days +%Y%m%d' ::: {0..52}
echo ${a[#]}
It has the bug, that it finds the next 53 Saturdays, and the last of those may not be in current year.
parset is part of GNU Parallel.
I didn't do much error checking, but here's another implementation.
Takes day of week and target year as arguments.
Gets the julian day of the first matching weekday requested -
gets the epoch seconds of noon on that day -
as long as the year matches what was requested, adds that date to the array and adds a week's worth of seconds to the tracking variable.
Lather, rinse, repeat until no longer in that year.
$: typeset -f alldays
alldays () { local dow=$1 year=$2 julian=1;
until [[ "$dow" == "$( date +%a -d $year-01-0$julian )" ]]; do (( julian++ )); done;
es=$( date +%s -d "12pm $year-01-0$julian" );
allhits=( $( while [[ $year == "$( date +%Y -d #$es )" ]]; do date +%Y%m%d -d #$es; (( es+=604800 )); done; ) )
}
$: time alldays Sat 1850
real 0m9.931s
user 0m1.025s
sys 0m6.695s
$: printf "%s\n" "${allhits[#]}"
18500105
18500112
18500119
18500126
18500202
18500209
18500216
18500223
18500302
18500309
18500316
18500323
18500330
18500406
18500413
18500420
18500427
18500504
18500511
18500518
18500525
18500601
18500608
18500615
18500622
18500629
18500706
18500713
18500720
18500727
18500803
18500810
18500817
18500824
18500831
18500907
18500914
18500921
18500928
18501005
18501012
18501019
18501026
18501102
18501109
18501116
18501123
18501130
18501207
18501214
18501221
18501228
I am trying to create a script in which 4 days ago date should be equal to to current date if it is not then add 1 more day and check. Below is the one i have created but still not clear about answer.
#!/bin/bash
batchdate=`date --date "4 day ago" '+%Y%m%d'`
matchdate=`date --date "today" '+%Y%m%d'`
for i in {0..4}
do
if [ $batchdate != $matchdate && $NEXT_DATE != $matchdate ]; then
NEXT_DATE=$(date +%Y%m%d -d "$batchdate + $i day")
echo "$NEXT_DATE"
break
fi
done
First, define a little helper function to avoid doing the same thing in slightly different ways:
get_date () {
date +%Y-%m-%d --date "$1"
}
Now, you have two variables: the current date, which will never change, and the starting date, which you will increment one day at a time until it matches the current date.
then=$(get_date "4 days ago")
now=$(get_date "today")
while [[ $then != $now ]]; do
then=$(get_date "$then + 1 day")
echo "$then"
done
I trying to print date between 2 dates using while loop in a bash script.
But when i execute i am getting below error:
test.sh: line 8: [: 02-12-14: integer expression expected
Below is my code, can anyone help me out
#!/bin/bash
sdate=02-12-14
edate=02-25-14
while [ "$sdate" -le "$edate" ]
do
echo $sdate
sdate=$(date +%m-%d-%y -d "$sdate + 1 day")
done
You should store them as timestamps:
#!/bin/bash
sdate=$(date -d '2014-02-12' +%s)
edate=$(date -d '2014-02-25' +%s)
while [[ sdate -le edate ]]; do
date -d "#$sdate" '+%m-%d-%y'
sdate=$(date -d "$(date -d "#${sdate}" ) + 1 day" +%s)
done
Output:
02-12-14
02-13-14
02-14-14
02-15-14
02-16-14
02-17-14
02-18-14
02-19-14
02-20-14
02-21-14
02-22-14
02-23-14
02-24-14
02-25-14
Always prefer [[ ]] over [ ] when it comes to conditional expressions in Bash. (( )) may also be a preference.
It requires GNU date. e.g. date --version = date (GNU coreutils) 8.21 ...
mm-dd-yy is not a format acceptable by date for input so I used yyyy-mm-dd which is acceptable.
Given a date in format 20130522, I need to generate a sequence of date+hour as below:
2013052112,2013052113,2013052114,...,2013052122,2013052123,
2013052200,2013052201,2013052202,...,2013052222,2013052223,
2013052300
in which the first date+hour is 12 hours before the given date and the last date+hour is the midnight in the next day of the given date.
I tried several ways but none of them is ideal. How to generate such a sequence in a clean way using shell script? Thanks!
--Edit--
Per your request, this is what I have so far:
day=20130522
begin=`date --date "$day -12 hours"`
begin=`date -d "${begin:0:8} ${begin:8:2}" +%s`
end=`date --date "$day +1 day"`
end=`date -d "${end:0:8} ${end:8:2}" +%s`
datestr=`date -d #${begin} +%Y%m%d%H`
let begin=$begin+3600
while [ $begin -le $end ]
do
hr=`date -d #${begin} +%Y%m%d%H`
datestr="$datestr,$hr"
let begin=$begin+3600
done
and this is what I got from above:
2013052100,2013052101,2013052102,...,2013052123,
2013052200,2013052201,2013052202,...,2013052223,
2013052300
You can use date and brace expansion:
date=20130522
echo $(date -d "-1 day $date" +%Y%m%d){12..23} \
"$date"{00..23} \
$(date -d "+1 day $date" +%Y%m%d)00
Output (wrapped):
2013052112 2013052113 2013052114 2013052115 2013052116 2013052117 2013052118 2013052119 2013052120
2013052121 2013052122 2013052123 2013052200 2013052201 2013052202 2013052203 2013052204 2013052205
2013052206 2013052207 2013052208 2013052209 2013052210 2013052211 2013052212 2013052213 2013052214
2013052215 2013052216 2013052217 2013052218 2013052219 2013052220 2013052221 2013052222 2013052223
2013052300
Your code was quite well. What I think is that you used so much bash conversion, while date is very powerful and handles in an easier way.
I rewrited something and now I get this:
day=20130522
begin=$(date --date "$day -12 hours" "+%s")
end=$(date --date "$day +1 day" "+%s")
hr=$(date --date "#$begin" "+%s")
while [[ $hr -lt $end ]]
do
hr=$(($hr + 3600))
echo $(date -d "#$hr" "+%Y%m%d %H")
done
$ ./script
20130521 13
20130521 14
.../...
20130522 22
20130522 23
20130523 00