Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

bash

unix

cron

I have to set the cronjob for 1st working day of every month which means the script should run on 1st working day of every month.

If suppose 1st working is an holiday then the script should run on the 2nd working day. For eg: Jan 1 2015 is holiday then the script should run on Jan 2 2015.

like image 330
Shirchabayshan Avatar asked Dec 30 '14 05:12

Shirchabayshan


People also ask

How do I schedule a cron to run on the first Sunday of every month?

You need to combine two approaches: a) Use cron to run a job every Sunday at 9:00am. b) At the beginning of once_a_week , compute the date and extract the day of the month via shell, Python, C/C++, ... and test that is within 1 to 7, inclusive. If so, execute the real script; if not, exit silently.

What is the use of * * * * * In cron?

It is a wildcard for every part of the cron schedule expression. So * * * * * means every minute of every hour of every day of every month and every day of the week .


1 Answers

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.

like image 73
John1024 Avatar answered Oct 22 '22 15:10

John1024