vadicherla
asked on
Shell Script
Hi
i have cronjob shell script which we want to run all week days in a year except first 3 business days of month and last two business days of month We dont want script not on this particular days. This applies all months in a year.
Can we do some modificaton to this script or modify the cron enty
current crontab entry
04 00 * * 1-5 /sdfdf/sdfd.sh
Thanks
i have cronjob shell script which we want to run all week days in a year except first 3 business days of month and last two business days of month We dont want script not on this particular days. This applies all months in a year.
Can we do some modificaton to this script or modify the cron enty
current crontab entry
04 00 * * 1-5 /sdfdf/sdfd.sh
Thanks
By the way, most of the code will work in most modern shells, but the array initialisation is a bit bash-specific (though it may work in other shells too). If it complains about the "dom=(0 3" line, replace it with
dom[0]=0
dom[1]=31
dom[2]=28
and so on up to
dom[12]=31
The "expr" statements could all also be replaced by neater shell versions, but I didn't want to be too bash-specific if I could help it!
dom[0]=0
dom[1]=31
dom[2]=28
and so on up to
dom[12]=31
The "expr" statements could all also be replaced by neater shell versions, but I didn't want to be too bash-specific if I could help it!
Excluding Leap Years, would this work for you?
04 00 4-29 1,3,5,7,8,10,12 1-5 /sdfdf/sdfd.sh
04 00 4-28 4,6,9,11 1-5 /sdfdf/sdfd.sh
04 00 4-26 2 1-5 /sdfdf/sdfd.sh
04 00 4-29 1,3,5,7,8,10,12 1-5 /sdfdf/sdfd.sh
04 00 4-28 4,6,9,11 1-5 /sdfdf/sdfd.sh
04 00 4-26 2 1-5 /sdfdf/sdfd.sh
I don't think you can do it sensibly with crontab entries alone. The trouble is that a line like:
04 00 4-26 2 1-5 /sdfdf/sdfd.sh
will run if day of month is 4 to 26 OR day of week is 1 to 5 (not AND).
So if the 1st is a Monday, it will run.
My code assumed that you stayed with the original "04 00 * * 1-5" entry, so the script was only called Monday to Friday (but it would be simple to add that check to the script if you preferred).
04 00 4-26 2 1-5 /sdfdf/sdfd.sh
will run if day of month is 4 to 26 OR day of week is 1 to 5 (not AND).
So if the 1st is a Monday, it will run.
My code assumed that you stayed with the original "04 00 * * 1-5" entry, so the script was only called Monday to Friday (but it would be simple to add that check to the script if you preferred).
ASKER
Hi Expert
Do you think it will easaier to implement if we change the script to run all 7 days a week except first 3 business days of month and last 2 business day of month??
Thanks
Do you think it will easaier to implement if we change the script to run all 7 days a week except first 3 business days of month and last 2 business day of month??
Thanks
In that case, you could modify serialband's solution to
04 00 4-29 1,3,5,7,8,10,12 * /sdfdf/sdfd.sh
04 00 4-28 4,6,9,11 * /sdfdf/sdfd.sh
04 00 4-26 2 * /sdfdf/sdfd.sh
with the limitation that it won't work exactly in leap years.
04 00 4-29 1,3,5,7,8,10,12 * /sdfdf/sdfd.sh
04 00 4-28 4,6,9,11 * /sdfdf/sdfd.sh
04 00 4-26 2 * /sdfdf/sdfd.sh
with the limitation that it won't work exactly in leap years.
Then at the top of the script have:
if [ $(date '+%u') -ge 6 ]; then
exit 0
fi
to avoid running the rest of the script on Saturday or Sunday.
Ah, take that back. The crontab solution stops the script running on the first three days of the month - not the first three *business* days. That's why my shell script does checking of the day of the week (the "if [ $(date '+%u' --date=${ymdate}${c0day}) -lt 6 ]" bit).
Note that my script doesn't cope with business holidays (e.g. January 1 is not a business day in many countries), but that would get quite complex!
Note that my script doesn't cope with business holidays (e.g. January 1 is not a business day in many countries), but that would get quite complex!
I've never done both day of the week and day of month together, so I forgot that it was an 'or', not an 'and' for that combination.
Maybe you could incorporate the test in the cron to simplify your subsequent tests within the script for the first 3 and last 2 business days.
04 00 4-29 1,3,5,7,8,10,12 * test $(date +$u) -ge 6 &&/sdfdf/sdfd.sh
04 00 4-28 4,6,9,11 * test $(date +$u) -ge 6 && /sdfdf/sdfd.sh
04 00 4-26 2 * test $(date +$u) -ge 6 && /sdfdf/sdfd.sh
Maybe you could incorporate the test in the cron to simplify your subsequent tests within the script for the first 3 and last 2 business days.
04 00 4-29 1,3,5,7,8,10,12 * test $(date +$u) -ge 6 &&/sdfdf/sdfd.sh
04 00 4-28 4,6,9,11 * test $(date +$u) -ge 6 && /sdfdf/sdfd.sh
04 00 4-26 2 * test $(date +$u) -ge 6 && /sdfdf/sdfd.sh
I'd be wary of making cron entries any more complex than they need to be (there's also quite a short line length limit in some of the crons I've used). And just to complicate matters, you'd have to escape the % in the "date +%u" bit because cron uses % as an end-of-line marker.
It would be just as easy to add that check in the script. If it does need to count business days rather than just days, you'll need my complicated code, and adding the "date +%u" check I gave a couple of replies ago would be a trivial addition.
It would be just as easy to add that check in the script. If it does need to count business days rather than just days, you'll need my complicated code, and adding the "date +%u" check I gave a couple of replies ago would be a trivial addition.
So, vadicherla, does the "business" days count mean that if, for example, the 1st and 2nd of the month were Saturday and Sunday, then the first three business days would be the 3rd, 4th and 5th, so you wouldn't run the script until Thursday the 6th?
Also, would you rather not insert this extra code into your existing script (the "/sdfdf/sdfd.sh" in your example)? In that case, you could have a script which just contains the date checking code, and if all of the tests pass, it could then run your original script - that would be very easy to set up (just let me know and I'll show you how).
Also, would you rather not insert this extra code into your existing script (the "/sdfdf/sdfd.sh" in your example)? In that case, you could have a script which just contains the date checking code, and if all of the tests pass, it could then run your original script - that would be very easy to set up (just let me know and I'll show you how).
ASKER
So, vadicherla, does the "business" days count mean that if, for example, the 1st and 2nd of the month were Saturday and Sunday, then the first three business days would be the 3rd, 4th and 5th, so you wouldn't run the script until Thursday the 6th?
This is correct.
Also, would you rather not insert this extra code into your existing script (the "/sdfdf/sdfd.sh" in your example)? In that case, you could have a script which just contains the date checking code, and if all of the tests pass, it could then run your original script - that would be very easy to set up (just let me know and I'll show you how).
Yes this will be a good solution
This is correct.
Also, would you rather not insert this extra code into your existing script (the "/sdfdf/sdfd.sh" in your example)? In that case, you could have a script which just contains the date checking code, and if all of the tests pass, it could then run your original script - that would be very easy to set up (just let me know and I'll show you how).
Yes this will be a good solution
OK, I've added some extra code to the end of the script. I've also fixed up a couple of bugs (the old code would have failed in September, oddly!), and added the "only run on business days" check that I mentioned earlier. Note that I have commented out the "echo" commands I had to say why it was executing. This is because cron commonly emails the user if a cron job produces any output (on the assumption that successful UNIX/Linux code usually produces no output - output implies a problem).
save this script as, say, busdaysonly.sh, make it executable, then your crontab entry would be
4 0 * * * /path/to/busdaysonly.sh /sdfdf/sdfd.sh
#!/bin/bash
# Exit if in first 3 business days of the month or last 2, or not a business day.
# If parameters are provided, they are run if the above tests do not exit.
sday=0 # number of business days we have counted
cday=0 # day number we are looking at now
tday=$(date '+%d') # today's day of the month
#tday=11 # temp for testing
maxstart=3
maxend=2
ymdate=$(date "+%Y/%m/") # start of date as YYYY/MM/
#ymdate=2014/04/ # temp for testing
mdate=$(date '+%m') # Month, Jan=01
#mdate=04 # for testing
mdate=$(echo $mdate | sed 's/^0//') # strip leading 0
ydate=$(date '+%Y') # Year, eg 2014
#ydate=2014 # for testing
# First check that this is a business day
if [ $(date '+%u') -ge 6 ]; then
# echo This is not a business day
exit 0
fi
# Now check whether today is in the first $maxstart days of the month
while [ $tday -gt $cday -a $sday -le $maxstart ]; do
cday=$(expr $cday + 1)
c0day=$(printf "%02d" $cday)
if [ $(date '+%u' --date=${ymdate}${c0day}) -lt 6 ]; then
sday=$(expr $sday + 1)
fi
done
if [ $sday -le $maxstart ]; then
# echo In first $maxstart business days - date $tday, bus days $sday, checked $cday days
exit 0
fi
# Now check the end of the month
# Get the last day of the month
dom=(0 31 28 31 30 31 30 31 31 30 31 30 31)
if [ ! \( $(expr $ydate % 4) -ne 0 -o \( $(expr $ydate % 400) -ne 0 -a $(expr $ydate % 100) -eq 0 \) \) ]; then
dom[2]=29
fi
cday=$(expr ${dom[${mdate}]} + 1)
sday=0
while [ $tday -lt $cday -a $sday -le $maxend ]; do
cday=$(expr $cday - 1)
c0day=$(printf "%02d" $cday)
if [ $(date '+%u' --date=${ymdate}${c0day}) -lt 6 ]; then
sday=$(expr $sday + 1)
fi
done
if [ $sday -le $maxend ]; then
# echo In last $maxend business days - date $tday, bus days $sday, checked $cday days
exit 0
fi
#Now, if a parameter has been provided, run it, and any parameters passed to it
if [ $# -ge 1 ]; then
cmd=$1
shift
exec $cmd "$@"
fi
save this script as, say, busdaysonly.sh, make it executable, then your crontab entry would be
4 0 * * * /path/to/busdaysonly.sh /sdfdf/sdfd.sh
ASKER
Hi
How we are going to handle the fedral holidays with this script.
How we are going to handle the fedral holidays with this script.
As I said above, adding holiday checking is a whole lot more complicated! It really depends on how automated you need it to be.
The best bet, and similar to a method I've used in a spreadsheet, is to have a file with all of the federal holiday dates over as many years as you are going to use this program, with one date per line in YYYY/MM/DD format. Then in the test that does the "date +%u... -lt 6" bit, also test that the date you are checking is not in that file. I'm not at a computer at the moment, but I'll test it out as soon as I can.
The best bet, and similar to a method I've used in a spreadsheet, is to have a file with all of the federal holiday dates over as many years as you are going to use this program, with one date per line in YYYY/MM/DD format. Then in the test that does the "date +%u... -lt 6" bit, also test that the date you are checking is not in that file. I'm not at a computer at the moment, but I'll test it out as soon as I can.
ASKER
thank you
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Just have this at the start of your shell script.
Open in new window