2

I need your help to contruct a cron job to run the second last working day of every month. I can do LW as shown below but i am not sure how to do second last. I need your help and advise here please.

@MWE has kindly provided me a possible solution but it does not seem to work in all test scenarios.

code:
#!/bin/bash
date
WEEKDAY=$(date +%u)
# If detect the montday in 2 days.
if [ $(date +%d -d "2 day") -eq 1 ] && [ ${WEEKDAY} -lt 5 ] ; then
   echo "This is the 2. last working day of the month"
# If detect the montday in 5 days.
elif [ $(date +%d -d "5 day") -eq 1 ] && [ ${WEEKDAY} -eq 5 ] ; then
   echo "This is the 2. last working day of the month"
else
  exit
fi

Test scenario: Ive amended the system date on the server to be 29th August 2019 (**this is the second last working date on the system)

the script in debug mode exits out:

[oracle@rdbauroral01v ~]$ bash -x ./crontest.sh
+ date
Thu Aug 29 13:28:20 UTC 2019
++ date +%u
+ WEEKDAY=4
++ date +%d -d '2 day'
+ '[' 31 -eq 1 ']'
++ date +%d -d '5 day'
+ '[' 03 -eq 1 ']'
+ exit

appreciate your help here..

1
  • 1
    Your best bet with this sort of unusual cron expression is to run daily and let the script itself handle the more complicated logic.
    – ceejayoz
    Jul 18 '19 at 15:08
1

Just as simple idea to solve it in the script not in crontab.:

Last day of a month is always this day, when tomorrow = 1. of a month.

That means: Let get out the current date from epoch in seconds, and add 24h hours. Then lets get out what day of month it is:

TIMESTAMP=$(date +%s)
TIMESTAMP_TOMORROW=$(( $TIMESTAMP + 86400 ))

Figure out the month day of tomorrow:

DAYOFMONTH=$(date --date="@${TIMESTAMP_TOMORROW}" +%e)

if DAYOFMONTH == 1 today is the last day of month. Do, what you want, then. if not == 1, exit.

Alternatives can be found here: https://stackoverflow.com/questions/6139189/cron-job-to-run-on-the-last-day-of-the-month

TODAY=`date +%d`
TOMORROW=`date +%d -d "1 day"`

# See if tomorrow's day is less than today's
if [ $TOMORROW -lt $TODAY ]; then
echo "This is the last day of the month"
# Do stuff...
fi

or:

0 23 28-31 * * [ `/bin/date -d +1day +\%d` -eq 1 ] && myscript.sh

Last but not Least. Multiply $(( $TIMESTAMP + 86400 * 2 )) , for the 2. last day.

or:

TOMORROW=$(date +%d -d "2 day")

or:

[ $(/bin/date -d +2day +\%d) -eq 1 ]
3
  • Apologies for my ignorance but the above would give be "second to last day of the month" but what i seek is "second to last weekday of the month"
    – nick
    Jul 18 '19 at 14:40
  • Well, Second last weekday .... is the 5. day of a week, right? So try to understand the way i go. In your case, find out, what day of wekk it is. Than verify, that tomorrow is between. 1 max. 6 of month. Depends on your setting, if weekday starts by sunday or monday.
    – user532085
    Jul 18 '19 at 14:42
  • Hi, apologies in advance, As i very new to unix, how do i test the next execution of dates of the above to know that it would do exactly how you have described? especially i am keen to test this logic as stated by you --- 0 23 28-31 * * [ /bin/date -d +1day +\%d -eq 1 ] && myscript.sh
    – nick
    Jul 18 '19 at 14:47
0

To get out the 2. last working day of month. %u start with day 1 at monday. %w with sunday.

  1. last Workingday is typically thursday. So the 4. weekday. We have to look now 6 days in to future. -> Means, last 2. Workingday of month must be before the 5.th day of month.
WEEKDAY=$(date +%u)
TOMORROW=$(date +%d -d "5 day")
if [ ${WEEKDAY} -eq 4 ] && [ $TOMORROW -lt 5 ]; then
echo "This is the 2. last working day of the month"
fi
0
0

In crontab you can limit execution to Weekdays and Monthdays. Both in combination are a good start. So you can ensure the script only runs on a workingday. On Monthday aware February (28 days etc.) or just 30 days. it doesn't end at 31 for every month! So maybe use day 20-31, to be safe.

     field          allowed values
          -----          --------------
          minute         0-59
          hour           0-23
          day of month   1-31
          month          1-12 (or names, see below)
          day of week    0-7 (0 or 7 is Sunday, or use names)

Crontabentry like:

0 0 20-31 * 1-5 ./scriptname

The part is simple to find out, wha ist the second 3rd or 4. Weekday. Why? The script runs by crontab only on Workingdays. So we needen't care about saturday or sunday. Alternate way, we could check if the Weekday $(date +%u) in 1-5. This are working days.

The code is now simple:

If in 2 days, it's the first day of month... its the second last working day. But, what about Saturday and Sunday?

You need an case now. From Monday to Thursday will allways follow a working day. So the rules, if it is in 2 days the 1. Monthday, it is the 2. Last Workingday. Only on Friday there must be the first of month in 5 days to be the second Workingday. Or the first of a month must be an Thuesday.

WEEKDAY=$(date +%e)
# 1. If detect the montday in 2 days.
if [ $(date +%d -d "2 day") -eq 1 ] && [ ${WEEKDAY} -lt 5 ] ; then
   echo "This is the 2. last working day of the month"
# 1. If detect the montday in 5 days.
elif [ $(date +%d -d "5 day") -eq 1 ] && [ ${WEEKDAY} -eq 5 ]
   echo "This is the 2. last working day of the month"
else 
  exit
fi

Hopefully i don't miss anything.

5
  • thanks. Someone suggested create cron 26 -31st check if if(tomorrow == last weekday) but im not sure how that is going to work?
    – nick
    Jul 18 '19 at 16:38
  • Will not work. 2. Last Weekday isn't last Workingday of month. See Example of January. Maybe the 30.01 is monday. Last Weekday is Friday so tomorrow will not be the last weekday but monday 30.01 second last Workday of month.
    – user532085
    Jul 18 '19 at 22:21
  • Done and reedited.
    – user532085
    Jul 18 '19 at 23:05
  • Hello, the above throws error ./cron_test2.sh: line 8: syntax error near unexpected token else' ./cron_test2.sh: line 8: else ' Also under which condition my job should run as both "if" statements echos "2nd last working day.
    – nick
    Jul 19 '19 at 9:25
  • okay the script syntax is okay. Do i still need to set the cron job as "0 0 20-31 * 1-5 ./scriptname" ?
    – nick
    Jul 19 '19 at 9:58
0

Do i still need to set the cron job as "0 0 20-31 * 1-5 ./scriptname"

No! But, does it make sense to execute it on any day?

28
  • 1
    Welcome to Server Fault! This does not answer the question. If you have another question, please ask it by clicking the Ask Question button. Jul 19 '19 at 13:12
  • Gerarld Schneider, it answers his question in a comment. But i'm not able to answer his comment directly. I'm realy sorry about this...
    – MWE
    Jul 19 '19 at 13:21
  • 2
    Unfortunately the StackExchange sites don't quite work this way - since your answer isn't an answer to the actual question, it's hard to connect it to the comment you're thinking of. The only advice I can give is to spend a little time here to answer questions, and you'll soon get enough reputation points to be able to comment properly.
    – Jenny D
    Jul 19 '19 at 13:34
  • Thisfore i added the "Quote" of the question in the comment.
    – MWE
    Jul 19 '19 at 13:39
  • 1
    @nick: Yes, please edit your question to contain the part MW is referring to. Answers on Server Fault must answer the question, not discuss something else, like comments.
    – Sven
    Jul 22 '19 at 12:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.