First run the date command:
$ date '+%x' 12/29/2014
%x specifies the date to display today's date in the current locale format. Using this exact format , put the list of holidays in a file called holidays . For instance:
$ cat holidays 01/01/2015 07/04/2015
Then create the following shell script:
#!/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 date representation (eg 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" /path/holidays then workday=Yes nworkdays=$((nworkdays+1)) else workday= fi done [ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command
where /path/command is replaced by any command that you want to run on the first business day of the month. Also, replace /path/holidays with the correct path to your holidays file.
Finally, tell cron to run the above script every day. Your command will be executed only on the first working day of the month.
How it works
Look at the core script:
for d in $(seq 1 $dom); do
Starts a cycle with variable d from 1 to the current day of the month.
today=$(date -d "$year-$month-$d" '+%x') # locale date representation (eg 12/31/99)
This sets today to the end date for day d this month and year.
dow=$(date -d "$year-$month-$d" '+%u') # day of week: 1-7 with 1=Monday, 7=Sunday
This sets the dow on the day of the week for day d with 1 = Monday and 7 = Sunday.
if [ "$dow" -le 5 ] && grep -vq "$today" /path/holidays
The test "$dow" -le 5 ] checks that day d is a weekday (from Monday to Friday). The grep -vq "$today" /path/holidays test grep -vq "$today" /path/holidays checks that the day d date is not displayed in the holidays file. If both tests are true, then day d is the working day, and then condition is satisfied:
then workday=Yes; nworkdays=$((nworkdays+1))
The offer then sets workday to Yes , and also increases the number of working days this month: nworkdays
else workday=
The else clause sets workday back to the empty string.
fi
fi signals the end of the if .
done
done means the end of the for loop.
[ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command
The last for loop was for today's date. Thus, if workday=Yes after the end of the cycle, then today is the working day. In addition, if nworkdays=1 , then today is the first working day of the month. If both conditions are true, your /path/command is executed.
source share