Set Cron Job for 1St Working Day of Every Month in Shell Scripting

Set Cron Job for 1st working day of every month in Shell Scripting

First, run the date command:

$ date '+%x'
> 12/29/2014

%x tells date to display today's date in the format of the current locale. Using that exact same format, put a list of holidays in a file called holidays. For example:

$ cat holidays
> 01/01/2015
> 07/04/2015

Next, 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'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" /path/holidays
then
workday=Yes
nworkdays=$((nworkdays+1))
else
workday=
fi
done
[ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command

How do I run a script for 1st working day of every month in cron?

First, run the date command:

$ date '+%x'
12/29/2014

%x tells date to display today's date in the format of the current locale. Using that exact same format, put a list of holidays in a file called holidays. For example:

$ cat holidays
01/01/2015
07/04/2015

Next, 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'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" /path/holidays
then
workday=Yes
nworkdays=$((nworkdays+1))
else
workday=
fi
done
[ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command

where /path/command is replaced by whatever command you want to run on the first working day of the month. Also, replace /path/holidays with the correct path to your holidays file.

Lastly, 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

Let's look at the core of the script:

  • for d in $(seq 1 $dom); do

    This starts a loop running the variable d from 1 to the current day-of-the-month.

  • today=$(date -d "$year-$month-$d" '+%x') # locale's date representation (e.g. 12/31/99)

    This sets today to the datestring for the day d of this month and year.

  • dow=$(date -d "$year-$month-$d" '+%u') # day of week: 1-7 with 1=Monday, 7=Sunday

    This sets dow to 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 ] verifies that day d is a weekday (Monday-Friday). The test grep -vq "$today" /path/holidays verifies that day d's date does not appear in the holidays file. If both tests are true, then day d is a work day and the then clause is executed:

  • then workday=Yes; nworkdays=$((nworkdays+1))

    The then clause sets workday to Yes and also increments the count of workdays so far this month: nworkdays

  • else workday=

    The else clause sets workday back to the empty string.

  • fi

    fi signals the end of the if statement.

  • done

    done signifies the end of the for loop.

  • [ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command

    The last loop in the for statement was for today's date. Thus, if workday=Yes after the loop ends, then today is a workday. Furthermore, if nworkdays=1, then today is the first workday of the month. If both conditions are true, then your command /path/command is executed.

Cron - How to run a job on the first weekday after a specific day of the month?

You can't define such logic in cron and the usual way is to add it in to the script you want to run. So run the script every day like this:

0 0 * * * /path/to/script.sh

and add inside

if [ "$(date +%d%m)" == "0101" ]
then rm -f /var/run/flag
fi
if [ $(date +%d) -ge 12 ] && [ $(date +%w) -gt 0 ] && [ $(date +%w) -lt 6 ] && [ ! -f /var/run/flag ]
then <do the work>
touch /var/run/flag
fi
exit

Also you should take care to run only once (as far as I understand)

schedule a cron job to run on 1st, 2nd, and 3rd tuesday of every month

An alternative would be to create main-script to run every Tuesday, verify that Tuesday is and that hour is accordingly invokes the appropriate secondary script.

0 7,9 * * 2 wget -q -O /dev/null http://site.com/main-script

I hope that is helpful.

Greetings.

How to schedule to run first Sunday of every month

You can put something like this in the crontab file:

00 09 * * 7 [ $(date +\%d) -le 07 ] && /run/your/script

The date +%d gives you the number of the current day, and then you can check if the day is less than or equal to 7. If it is, run your command.

If you run this script only on Sundays, it should mean that it runs only on the first Sunday of the month.

Remember that in the crontab file, the formatting options for the date command should be escaped.

How to run cronjob on every month first friday?

This is because when you specify a day of month and day of week, cron will execute the job when EITHER of those constraints are true. From the man page for crontab (5):

   Note: The day of a command's execution can be specified by two fields —
day of month, and day of week. If both fields are restricted (i.e.,
aren't *), the command will be run when either field matches the cur‐
rent time. For example,
``30 4 1,15 * 5'' would cause a command to be run at 4:30 am on the 1st
and 15th of each month, plus every Friday.

There isn't a direct way in cron to do what you want, but cron : how to schedule to run first Sunday of every month describes a workaround by using cron to run your script e.g. every Friday and then calculating in the script if the day of month is in the range 1-7, and only continuing when that is the case.

In response to the comment about using 5 rather than Fri to specify day of week: using Fri is OK, as the man page says:

   Months or days of the week can be specified by name.

How to schedule a cron for the first Thursday of every month

the answer:

0 15 * * 4 [ $(date +\%d) -le 7 ] && command

the explanation:

First of all you need to realize that the first Thursday of the month will always have a day of the month that is in the set {1,2,3,4,5,6,7}. That is simply because there are only 7 days in a week. And thus the first Thursday cannot be have a day that is bigger then 7. The same holds evidently for any other weekday such as Tuesday or Saturday.

The command that cron will execute consists of two parts:

  • [ $(date "+\%d") -le 7 ]: This is a simple test that checks if the day of the month is smaller than 7. It essentially checks if we are in the first week of the month. The command date -d "+%d" returns the day of the month as a two-digit number (01,02,03,...,31) and is a string. The test command, here written in an alternative form with square brackets [ ... ] does a check to see if the integer comming from date is smaller then or equal to 7. You can read more on this when typing man test in a terminal.

  • command: this is the command that is going to be executed if the previous test is successful. I.e. if we are in the first week of the month. The reason why this will only execute if the test command is successful, is because of the &&. A command of the form cmd1 && cmd2 will execute cmd1 and only when that one is successful will it execute cmd2.

So since we now have the command, we can now build our crontab file. With a bit more comments (parts starting with #, you can write it as:

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7)
# | | | | |
# * * * * * command to be executed
0 15 * * 4 [ $(date +\%d) -le 07 ] && command

The above means, execute the above command at minute 0 of the 15th hour of any Thursday. And since the command contains the test for the first week, it will only run on the first Thursday of the month.

Schedule Cron to skip first Saturday of every month

Since there seem to be no option in Cron.
I'm going with script for the above need.

**if [ $(date +%d) -le 7 ] && [ $(date +%u) -eq 1 ] ;**

[ $(date +%d) -le 7 ] - Checks if the days fall in first 7 days of month

[ $(date +%u) -eq 6 ] - Checks if day is equal to Saturday

Thanks.



Related Topics



Leave a reply



Submit