Reputation: 125
I'm making a backup script in which I need to find the last Saturday of each month.
I've tried different approaches to finding the day itself, which works splendidly themselves.
The problem is, when I try putting them into my script I always get the error code
./test.sh: line 13: [: 29: integer expression expected
.
This is my code:
#!/bin/bash
LASTSAT=$(ncal | grep Sa | awk '{print$(NF-0)}')
SATURDAY="6"
DAY=$(date +"%u")
DATE=$(date +"%d")
echo "$DAY"
echo "$DATE"
echo "$LASTSAT"
if [ $DATE -eq $LASTSAT ]
then
echo "sista lördagen..."
fi
I got the tip to change the if statements to [ "$DATE" = "$LASTSAT" ]
which erased the error itself, but the script will somehow not equal 27 to 27 (to take this month as an example).
I also tried another approach to finding the last Saturday which was LASTSAT=$(cal|awk '{if(NF==7){SAT=$7}};END{print SAT}')
, but it returns the exact same error if I use -eq and doesn't equal 27 to 27 using " with =
I'm very confused and out of ideas and I have searched the internet and copied the exact lines others been using but it all ends up the same.
What am I doing wrong?
Upvotes: 3
Views: 11374
Reputation: 1
Here is solution
if [[ $(date +"%a") = "Sat" ]] && [[$(date -d "+7 days" +%m) != $(date +%m)]]
then
echo "Last saturday of month"
fi
Upvotes: 0
Reputation: 1
How about this one:
if [ `date +%u` = 7 ] && [ `date +%m` != `date -d +week +%m` ]; then
echo "sista lördagen..."
fi
... or simply via crontab:
0 0 * * 0 [ `date +\%m` != `date -d +week +\%m` ] && /path/to/backup.sh
Upvotes: -1
Reputation: 1
#!/bin/bash
set -e
if [ "$#" -ne 2 ]; then
echo "Usage: weekDayOfMonth.sh [weekOfMonth 1..4] [DayOfWeek where Sun=1]"
exit 2;
fi
weekOfMonth=$1
dayOfWeek=$2 #starts with Sun(=1)
echo "weekOfMonth: $weekOfMonth";
echo "dayOfWeek: $dayOfWeek";
# cal starts with Sun, 3rd column is for Tue, 2nd row is 2nd Tue of month:
# Sun=1, dayIdx=0
# Mon=2, dayIdx=3
# Tue=3, dayIdx=6
# Wed=4, dayIdx=9
dayIdx=$(((dayOfWeek-1)*3))
expectedDayOfMonth=$(cal -s | sed "s/^.\{$dayIdx\}\(.\{3\}\).*$/\1/" | sed 's/^[ ]//g' | grep -o '[0-9]*' | head -$weekOfMonth | tail -1)
todaysDay=$(date +%d | sed 's/^0*//')
echo "expectedDayOfMonth: $expectedDayOfMonth";
echo "todaysDay: $todaysDay";
if [ ${expectedDayOfMonth} -ne ${todaysDay} ]; then
echo "Today is NOT requested day of month, exiting with error code.";
exit 1;
fi
Upvotes: 0
Reputation: 46846
You can easily get the last Saturday of the month using the date
command, which spits out data in strftime()
format. But date
's syntax will depend on your operating system.
In FreeBSD or OSX, there's a -v
option to "adjust" the date that gives you lots of control:
[ghoti@pc ~]$ date -v+1m -v1d -v6w '+%a %d %b %Y'
Sat 03 Nov 2012
[ghoti@pc ~]$ date -v+1m -v1d -v6w -v-1w '+%a %d %b %Y'
Sat 27 Oct 2012
The idea here is that we'll move 1 month forward (+1m
), back up to the first of the month (1d
), then move to the 6th day of the week which is Saturday (6w
). For demonstration purposes, the first line shows the first saturday of next month, and the second line shows the date one week (-v-1w
) earlier.
Alternately, if you wanted to put some math in your bash script, you could do something like this:
#!/usr/local/bin/bash
# Get day-of-the-week for the first-of-the-month:
firstofmonth=$(date -j -v+1m -v1d '+%u')
# ^
# + This is the relative month to current.
# Subtract this from 7 to find the date of the month
firstsaturday=$((7 - $firstofmonth))
# 7 days before that will be the last Saturday of the previous month
lastsaturday=$(date -j -v+1m -v${firstsaturday}d -v-7d '+%Y-%m-%d')
With the -v
option, 1 is January, 2 is February, etc. Or it can be relative, as I've shown here, with +1 for next month, -1 for last month, etc.
In Linux, date uses a -d
option that interprets a text description of the date. So:
#!/bin/bash
firstofmonth=$(date -d '+1 months' '+%Y%m01')
firstsaturday=$(date -d "$firstofmonth" '+%Y-%m')-$(( 7 - $(date -d "$firstofmonth" '+%u') ))
lastsaturday=$(date -d "$firstsaturday -7 days" '+%d')
Note that if you're using cron, you can simplify this. You know that the last Saturday will sit within the last 7 days of the month, so we can start by using cron to limit things to Saturday, then check for the last of the month within the script. This will run the script every Saturday, but it will do nothing except when it's supposed to. The cron tab would be, say,
# ↙ "0 0"=midnight
0 0 * * 0 /path/to/script.sh
# ↖ 0=Sunday
And script.sh
would start with:
#!/bin/bash
if [[ $(date '+%d' -lt $(date -d "$(date -d '+1 month' '+%Y%m01') -7 days" '+%d') ]]; then
exit
fi
You could also put this test within the crontab, though it would look a little uglier because you'd need to escape the percent signs:
0 0 * * 0 \
test $(date '+\%d') -ge $(date -d "$(date -d '+1 month' '+\%Y\%m01') -7 days" '+\%d') \
&& /path/to/command
Upvotes: 3
Reputation: 241701
How about this one:
last_saturday ()
{
local Format;
if [[ $1 =~ ^\+.* ]]; then
Format=$1;
shift;
fi;
local FirstOfNext="${1:-$(date +%B)} 1 $2 + 1 month";
date $Format -d "$FirstOfNext - 1 day -
$(($(date +%u -d "$FirstOfNext") % 7)) day"
}
eg:
$ last_saturday
Sat Oct 27 00:00:00 PET 2012
$ last_saturday November
Sat Nov 24 00:00:00 PET 2012
$ last_saturday June
Sat Jun 23 00:00:00 PET 2012
$ last_saturday June 2013
Sat Jun 29 00:00:00 PET 2013
$ last_saturday +%Y-%m-%d June 2013
2013-06-29
Upvotes: 1
Reputation: 54392
Here's one way to print the last Saturday in each month using date
:
for i in {1..12}; do
for j in {1..7}; do
date=$(date -d "$i/1 + 1 month - $j day" +"%w %F")
# day of week (1..7); 1 is Monday
if [ ${date:0:1} -eq 6 ]; then
echo ${date:2}
fi
done
done
Results:
2012-01-28
2012-02-25
2012-03-31
2012-04-28
2012-05-26
2012-06-30
2012-07-28
2012-08-25
2012-09-29
2012-10-27
2012-11-24
2012-12-29
If you'd just like to find the last Saturday in the current month, try:
for j in {1..7}; do
month=$(date +"%m")
date=$(date -d "$month/1 + 1 month - $j day" +"%w %F")
# day of week (1..7); 1 is Monday
if [ ${date:0:1} -eq 6 ]; then
echo ${date:2}
fi
done
Result:
2012-10-27
Please note, that you can change the output format of these results in the above scripts simply by changing %F
to any of the formats date
has to offer. See man date
.
Upvotes: 2
Reputation: 8711
During testing I changed the target day and some of the variable names, but the following script works, for the next-to-last Sunday of the month. The critical change, relative to your script, was adding the -h
switch to ncal
, to turn off highlighting of the current day. The highlighting characters apparently come through when awk
prints the field, but aren't visible when you do the echo
s. Note, you can drop the grep
after ncal
via an awk
match.
#!/bin/bash
DoDay=$(ncal -h |awk '/Su/ {print $(NF-1)}')
Datum=$(date +%d)
echo $Datum Datum
echo $DoDay DoDay
if [[ $Datum == $DoDay ]]
then
echo "sista lördagen..."
else
echo "doh"
fi
Upvotes: 3
Reputation: 470
The script works fine on my System (Ubuntu - Bash $).
I just modified the script to print "!sista lördagen..." if the day wasn't the last saturday and this was the output:
$sh abc.sh
7
21
27
!sista lordagen...
Upvotes: 0