Schedule the last day of every month












9















I read from an instruction to schedule a script on the last day of the month:




Note:

The astute reader might be wondering just how you would be able to set a command to execute on the last day of every month because you can’t set the dayofmonth value to cover every month. This problem has plagued Linux and Unix programmers, and has spawned quite a few different solutions. A common method is to add an if-then statement that uses the date command to check if tomorrow’s date is 01:



00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


This checks every day at 12 noon to see if it's the last day of the month, and if so, cron runs the command.




enter image description here



How does [`date +%d -d tomorrow` = 01 ] work?

Is it correct to state then; command1?










share|improve this question

























  • Are you sure that's verbatim what it says? As written here it in fact doesn't work.

    – Michael Homer
    Oct 29 '18 at 3:09











  • I posted the snapshot.@MichaelHomer

    – JawSaw
    Oct 29 '18 at 3:12











  • Thanks! I've fiddled with the formatting to make it match - it's still not quite right, but it is what the picture says.

    – Michael Homer
    Oct 29 '18 at 3:13






  • 1





    Missing ; endif?

    – danblack
    Oct 29 '18 at 3:54











  • It doesn't work. It contains syntax errors: No space after [ and no fi at the end. Also, % is special in crontabs.

    – Kusalananda
    Oct 29 '18 at 8:29


















9















I read from an instruction to schedule a script on the last day of the month:




Note:

The astute reader might be wondering just how you would be able to set a command to execute on the last day of every month because you can’t set the dayofmonth value to cover every month. This problem has plagued Linux and Unix programmers, and has spawned quite a few different solutions. A common method is to add an if-then statement that uses the date command to check if tomorrow’s date is 01:



00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


This checks every day at 12 noon to see if it's the last day of the month, and if so, cron runs the command.




enter image description here



How does [`date +%d -d tomorrow` = 01 ] work?

Is it correct to state then; command1?










share|improve this question

























  • Are you sure that's verbatim what it says? As written here it in fact doesn't work.

    – Michael Homer
    Oct 29 '18 at 3:09











  • I posted the snapshot.@MichaelHomer

    – JawSaw
    Oct 29 '18 at 3:12











  • Thanks! I've fiddled with the formatting to make it match - it's still not quite right, but it is what the picture says.

    – Michael Homer
    Oct 29 '18 at 3:13






  • 1





    Missing ; endif?

    – danblack
    Oct 29 '18 at 3:54











  • It doesn't work. It contains syntax errors: No space after [ and no fi at the end. Also, % is special in crontabs.

    – Kusalananda
    Oct 29 '18 at 8:29
















9












9








9


2






I read from an instruction to schedule a script on the last day of the month:




Note:

The astute reader might be wondering just how you would be able to set a command to execute on the last day of every month because you can’t set the dayofmonth value to cover every month. This problem has plagued Linux and Unix programmers, and has spawned quite a few different solutions. A common method is to add an if-then statement that uses the date command to check if tomorrow’s date is 01:



00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


This checks every day at 12 noon to see if it's the last day of the month, and if so, cron runs the command.




enter image description here



How does [`date +%d -d tomorrow` = 01 ] work?

Is it correct to state then; command1?










share|improve this question
















I read from an instruction to schedule a script on the last day of the month:




Note:

The astute reader might be wondering just how you would be able to set a command to execute on the last day of every month because you can’t set the dayofmonth value to cover every month. This problem has plagued Linux and Unix programmers, and has spawned quite a few different solutions. A common method is to add an if-then statement that uses the date command to check if tomorrow’s date is 01:



00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


This checks every day at 12 noon to see if it's the last day of the month, and if so, cron runs the command.




enter image description here



How does [`date +%d -d tomorrow` = 01 ] work?

Is it correct to state then; command1?







shell-script cron date test






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 30 '18 at 16:41









Jeff Schaller

42.5k1158135




42.5k1158135










asked Oct 29 '18 at 2:59









JawSawJawSaw

984518




984518













  • Are you sure that's verbatim what it says? As written here it in fact doesn't work.

    – Michael Homer
    Oct 29 '18 at 3:09











  • I posted the snapshot.@MichaelHomer

    – JawSaw
    Oct 29 '18 at 3:12











  • Thanks! I've fiddled with the formatting to make it match - it's still not quite right, but it is what the picture says.

    – Michael Homer
    Oct 29 '18 at 3:13






  • 1





    Missing ; endif?

    – danblack
    Oct 29 '18 at 3:54











  • It doesn't work. It contains syntax errors: No space after [ and no fi at the end. Also, % is special in crontabs.

    – Kusalananda
    Oct 29 '18 at 8:29





















  • Are you sure that's verbatim what it says? As written here it in fact doesn't work.

    – Michael Homer
    Oct 29 '18 at 3:09











  • I posted the snapshot.@MichaelHomer

    – JawSaw
    Oct 29 '18 at 3:12











  • Thanks! I've fiddled with the formatting to make it match - it's still not quite right, but it is what the picture says.

    – Michael Homer
    Oct 29 '18 at 3:13






  • 1





    Missing ; endif?

    – danblack
    Oct 29 '18 at 3:54











  • It doesn't work. It contains syntax errors: No space after [ and no fi at the end. Also, % is special in crontabs.

    – Kusalananda
    Oct 29 '18 at 8:29



















Are you sure that's verbatim what it says? As written here it in fact doesn't work.

– Michael Homer
Oct 29 '18 at 3:09





Are you sure that's verbatim what it says? As written here it in fact doesn't work.

– Michael Homer
Oct 29 '18 at 3:09













I posted the snapshot.@MichaelHomer

– JawSaw
Oct 29 '18 at 3:12





I posted the snapshot.@MichaelHomer

– JawSaw
Oct 29 '18 at 3:12













Thanks! I've fiddled with the formatting to make it match - it's still not quite right, but it is what the picture says.

– Michael Homer
Oct 29 '18 at 3:13





Thanks! I've fiddled with the formatting to make it match - it's still not quite right, but it is what the picture says.

– Michael Homer
Oct 29 '18 at 3:13




1




1





Missing ; endif?

– danblack
Oct 29 '18 at 3:54





Missing ; endif?

– danblack
Oct 29 '18 at 3:54













It doesn't work. It contains syntax errors: No space after [ and no fi at the end. Also, % is special in crontabs.

– Kusalananda
Oct 29 '18 at 8:29







It doesn't work. It contains syntax errors: No space after [ and no fi at the end. Also, % is special in crontabs.

– Kusalananda
Oct 29 '18 at 8:29












3 Answers
3






active

oldest

votes


















15














That is a quote from the book "Linux Command Line and Shell Scripting Bible" by Richard Blum, Christine Bresnahan pp 442, Third Edition, John Wiley & Sons ©2015.



Yes, that is what it says, but that is wrong/incomplete:




  • Missing a closing fi.

  • Needs space between [ and the following `.

  • It is strongly recommended to use $(…) instead of `…`.

  • It is important that you use quotes around expansions like "$(…)"

  • There is an additional ; after then


How do I know? (well, by experience ☺ ) but you can try Shellcheck. Paste the code from the book (after the asterisks) and it will show you the errors listed above plus a "missing shebang". An script without any errors in Shellcheck is this:




#!/bin/sh
if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi



That site works because what was written is "shell code". That is a syntax that works in many shells.



Some issues that shellcheck doesn't mention are:




  • It is assuming that the date command is the GNU date version. The one with a -d option that accepts tomorrow as a value (busybox has a -d option but doesn't understand tomorrow and BSD has a -d option but is not related to "display" of time).


  • It is better to set the format after all the options date -d tomorrow +'%d'.


  • The cron start time is always in local time, that may make one job start 1 hour earlier of later than an exact day count if the DST (daylight saving time) got set or unset.



What we got done is a shell script which could be called with cron. We can further modify the script to accept arguments of the program or command to execute, like this (finally, the correct code):



#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"


Call this script end_of_month.sh and the call in cron is simply:



00 12 28-31 * * /path/to/script/end_of_month.sh command


That would run the script end_of_month (which internally will check that the day is the last day of the month) only on the days 28, 29, 30 and 31. There is no need to check for end of month on any other day.



Make sure the correct path is included. The PATH inside cron will not (not likely) be the same as the user PATH.



Note that there is one end of month script tested (as indicated below) that could call many other utilities or scripts.



This will also avoid the additional problem that cron generates with the full command line:




  • Cron splits the command line on any % even if quoted either with ' or " (only a works here). That is a common way in which cron jobs fail.


You can test if end_of_month.sh script works correctly on some date (without waiting to the end of the month to discover it doesn't work) by testing it with faketime:



$ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
Command will be executed....





share|improve this answer


























  • ast-open date (or the date builtin of ksh93 if ksh93 was built as part of ast-open) does support date -d tomorrow +%s or date +%s tomorrow).

    – Stéphane Chazelas
    Oct 29 '18 at 10:02






  • 3





    One could argue that the stuff relating to the scheduling of the script should be separated out into the crontab, while the operational parts remain in the separate script.

    – Kusalananda
    Oct 29 '18 at 10:13











  • One could argue that it is the shell what is doing the scheduling, not cron. @Kusalananda

    – Isaac
    Oct 29 '18 at 10:21






  • 1





    Experience has proven (many times) that it is a lot better to test the script correctly running with faketime than it is to wait till the end of the month to find that the scheduled job didn't work. Like discovering that * * * * * echo "$(date -u +'date %c')" >>~/testfile wont work because one forgot to quote the % (which becomes difficult to debug if only one try every month is posible). @Kusalananda

    – Isaac
    Oct 29 '18 at 10:32






  • 1





    Or one could follow the UNIX-approach and let one tool do one task: Why not have two scripts? You can easily test them in separation, and you can reuse them. Your crontab becomes 00 12 28-31 * * onlastdayofmonth.sh mysuperscript.sh

    – mhutter
    Oct 31 '18 at 15:17



















8














Assuming that the syntax errors are fixed, and the command reformulated slightly to be less verbose:



00 12 28-31 * * [ "$( date -d tomorrow +%d )" != "01" ] || command1


This runs date +%d -d tomorrow (assuming that it's GNU date that is used) to get tomorrow's date as a two-digit number. If the number isn't 01, then today is not the last day of the month. In that case, the tests succeeds and command1 is not executed. The job is run at noon on the days that could possibly be the last day of the month.



The original command:



00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


This has a few issues:




  • No space after [.

  • A ; directly after then.


  • % is special in cron job specifications and must be escaped as % (see man 5 crontab).

  • There is no final fi at the end that matches up with the if.






share|improve this answer





















  • 2





    The problem with using [ ... ] && command1 instead of if... is that on days that are not the last day of the month, the cron job will end with a non-zero exit status and that failure may have to be reported. Using [ "$(...)" != 01 ] || command1 is another way to avoid the problem.

    – Stéphane Chazelas
    Oct 29 '18 at 9:24








  • 1





    Another problem with the original code is the ; between then and command1.

    – Stéphane Chazelas
    Oct 29 '18 at 9:26











  • @StéphaneChazelas Another reason why I dislike one-liners, they are difficult to read.

    – Kusalananda
    Oct 29 '18 at 10:10











  • The time difference between consecutive runs of the command might not be an integer amount of (24 hour) days as a DST change will shift the start time of cron.

    – Isaac
    Oct 29 '18 at 12:31






  • 3





    @cat It doesn't matter how you quote, either " or ' (except ), the percent sign % will make cron break the line in two parts. That is one usual way to get cron to fail.

    – Isaac
    Oct 29 '18 at 13:53





















0














Schedule the last day of every month?
you can try 0 0 15,L * *





share








New contributor




Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "106"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f478335%2fschedule-the-last-day-of-every-month%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    15














    That is a quote from the book "Linux Command Line and Shell Scripting Bible" by Richard Blum, Christine Bresnahan pp 442, Third Edition, John Wiley & Sons ©2015.



    Yes, that is what it says, but that is wrong/incomplete:




    • Missing a closing fi.

    • Needs space between [ and the following `.

    • It is strongly recommended to use $(…) instead of `…`.

    • It is important that you use quotes around expansions like "$(…)"

    • There is an additional ; after then


    How do I know? (well, by experience ☺ ) but you can try Shellcheck. Paste the code from the book (after the asterisks) and it will show you the errors listed above plus a "missing shebang". An script without any errors in Shellcheck is this:




    #!/bin/sh
    if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi



    That site works because what was written is "shell code". That is a syntax that works in many shells.



    Some issues that shellcheck doesn't mention are:




    • It is assuming that the date command is the GNU date version. The one with a -d option that accepts tomorrow as a value (busybox has a -d option but doesn't understand tomorrow and BSD has a -d option but is not related to "display" of time).


    • It is better to set the format after all the options date -d tomorrow +'%d'.


    • The cron start time is always in local time, that may make one job start 1 hour earlier of later than an exact day count if the DST (daylight saving time) got set or unset.



    What we got done is a shell script which could be called with cron. We can further modify the script to accept arguments of the program or command to execute, like this (finally, the correct code):



    #!/bin/sh
    [ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
    [ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
    exec "$@"


    Call this script end_of_month.sh and the call in cron is simply:



    00 12 28-31 * * /path/to/script/end_of_month.sh command


    That would run the script end_of_month (which internally will check that the day is the last day of the month) only on the days 28, 29, 30 and 31. There is no need to check for end of month on any other day.



    Make sure the correct path is included. The PATH inside cron will not (not likely) be the same as the user PATH.



    Note that there is one end of month script tested (as indicated below) that could call many other utilities or scripts.



    This will also avoid the additional problem that cron generates with the full command line:




    • Cron splits the command line on any % even if quoted either with ' or " (only a works here). That is a common way in which cron jobs fail.


    You can test if end_of_month.sh script works correctly on some date (without waiting to the end of the month to discover it doesn't work) by testing it with faketime:



    $ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
    Command will be executed....





    share|improve this answer


























    • ast-open date (or the date builtin of ksh93 if ksh93 was built as part of ast-open) does support date -d tomorrow +%s or date +%s tomorrow).

      – Stéphane Chazelas
      Oct 29 '18 at 10:02






    • 3





      One could argue that the stuff relating to the scheduling of the script should be separated out into the crontab, while the operational parts remain in the separate script.

      – Kusalananda
      Oct 29 '18 at 10:13











    • One could argue that it is the shell what is doing the scheduling, not cron. @Kusalananda

      – Isaac
      Oct 29 '18 at 10:21






    • 1





      Experience has proven (many times) that it is a lot better to test the script correctly running with faketime than it is to wait till the end of the month to find that the scheduled job didn't work. Like discovering that * * * * * echo "$(date -u +'date %c')" >>~/testfile wont work because one forgot to quote the % (which becomes difficult to debug if only one try every month is posible). @Kusalananda

      – Isaac
      Oct 29 '18 at 10:32






    • 1





      Or one could follow the UNIX-approach and let one tool do one task: Why not have two scripts? You can easily test them in separation, and you can reuse them. Your crontab becomes 00 12 28-31 * * onlastdayofmonth.sh mysuperscript.sh

      – mhutter
      Oct 31 '18 at 15:17
















    15














    That is a quote from the book "Linux Command Line and Shell Scripting Bible" by Richard Blum, Christine Bresnahan pp 442, Third Edition, John Wiley & Sons ©2015.



    Yes, that is what it says, but that is wrong/incomplete:




    • Missing a closing fi.

    • Needs space between [ and the following `.

    • It is strongly recommended to use $(…) instead of `…`.

    • It is important that you use quotes around expansions like "$(…)"

    • There is an additional ; after then


    How do I know? (well, by experience ☺ ) but you can try Shellcheck. Paste the code from the book (after the asterisks) and it will show you the errors listed above plus a "missing shebang". An script without any errors in Shellcheck is this:




    #!/bin/sh
    if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi



    That site works because what was written is "shell code". That is a syntax that works in many shells.



    Some issues that shellcheck doesn't mention are:




    • It is assuming that the date command is the GNU date version. The one with a -d option that accepts tomorrow as a value (busybox has a -d option but doesn't understand tomorrow and BSD has a -d option but is not related to "display" of time).


    • It is better to set the format after all the options date -d tomorrow +'%d'.


    • The cron start time is always in local time, that may make one job start 1 hour earlier of later than an exact day count if the DST (daylight saving time) got set or unset.



    What we got done is a shell script which could be called with cron. We can further modify the script to accept arguments of the program or command to execute, like this (finally, the correct code):



    #!/bin/sh
    [ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
    [ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
    exec "$@"


    Call this script end_of_month.sh and the call in cron is simply:



    00 12 28-31 * * /path/to/script/end_of_month.sh command


    That would run the script end_of_month (which internally will check that the day is the last day of the month) only on the days 28, 29, 30 and 31. There is no need to check for end of month on any other day.



    Make sure the correct path is included. The PATH inside cron will not (not likely) be the same as the user PATH.



    Note that there is one end of month script tested (as indicated below) that could call many other utilities or scripts.



    This will also avoid the additional problem that cron generates with the full command line:




    • Cron splits the command line on any % even if quoted either with ' or " (only a works here). That is a common way in which cron jobs fail.


    You can test if end_of_month.sh script works correctly on some date (without waiting to the end of the month to discover it doesn't work) by testing it with faketime:



    $ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
    Command will be executed....





    share|improve this answer


























    • ast-open date (or the date builtin of ksh93 if ksh93 was built as part of ast-open) does support date -d tomorrow +%s or date +%s tomorrow).

      – Stéphane Chazelas
      Oct 29 '18 at 10:02






    • 3





      One could argue that the stuff relating to the scheduling of the script should be separated out into the crontab, while the operational parts remain in the separate script.

      – Kusalananda
      Oct 29 '18 at 10:13











    • One could argue that it is the shell what is doing the scheduling, not cron. @Kusalananda

      – Isaac
      Oct 29 '18 at 10:21






    • 1





      Experience has proven (many times) that it is a lot better to test the script correctly running with faketime than it is to wait till the end of the month to find that the scheduled job didn't work. Like discovering that * * * * * echo "$(date -u +'date %c')" >>~/testfile wont work because one forgot to quote the % (which becomes difficult to debug if only one try every month is posible). @Kusalananda

      – Isaac
      Oct 29 '18 at 10:32






    • 1





      Or one could follow the UNIX-approach and let one tool do one task: Why not have two scripts? You can easily test them in separation, and you can reuse them. Your crontab becomes 00 12 28-31 * * onlastdayofmonth.sh mysuperscript.sh

      – mhutter
      Oct 31 '18 at 15:17














    15












    15








    15







    That is a quote from the book "Linux Command Line and Shell Scripting Bible" by Richard Blum, Christine Bresnahan pp 442, Third Edition, John Wiley & Sons ©2015.



    Yes, that is what it says, but that is wrong/incomplete:




    • Missing a closing fi.

    • Needs space between [ and the following `.

    • It is strongly recommended to use $(…) instead of `…`.

    • It is important that you use quotes around expansions like "$(…)"

    • There is an additional ; after then


    How do I know? (well, by experience ☺ ) but you can try Shellcheck. Paste the code from the book (after the asterisks) and it will show you the errors listed above plus a "missing shebang". An script without any errors in Shellcheck is this:




    #!/bin/sh
    if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi



    That site works because what was written is "shell code". That is a syntax that works in many shells.



    Some issues that shellcheck doesn't mention are:




    • It is assuming that the date command is the GNU date version. The one with a -d option that accepts tomorrow as a value (busybox has a -d option but doesn't understand tomorrow and BSD has a -d option but is not related to "display" of time).


    • It is better to set the format after all the options date -d tomorrow +'%d'.


    • The cron start time is always in local time, that may make one job start 1 hour earlier of later than an exact day count if the DST (daylight saving time) got set or unset.



    What we got done is a shell script which could be called with cron. We can further modify the script to accept arguments of the program or command to execute, like this (finally, the correct code):



    #!/bin/sh
    [ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
    [ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
    exec "$@"


    Call this script end_of_month.sh and the call in cron is simply:



    00 12 28-31 * * /path/to/script/end_of_month.sh command


    That would run the script end_of_month (which internally will check that the day is the last day of the month) only on the days 28, 29, 30 and 31. There is no need to check for end of month on any other day.



    Make sure the correct path is included. The PATH inside cron will not (not likely) be the same as the user PATH.



    Note that there is one end of month script tested (as indicated below) that could call many other utilities or scripts.



    This will also avoid the additional problem that cron generates with the full command line:




    • Cron splits the command line on any % even if quoted either with ' or " (only a works here). That is a common way in which cron jobs fail.


    You can test if end_of_month.sh script works correctly on some date (without waiting to the end of the month to discover it doesn't work) by testing it with faketime:



    $ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
    Command will be executed....





    share|improve this answer















    That is a quote from the book "Linux Command Line and Shell Scripting Bible" by Richard Blum, Christine Bresnahan pp 442, Third Edition, John Wiley & Sons ©2015.



    Yes, that is what it says, but that is wrong/incomplete:




    • Missing a closing fi.

    • Needs space between [ and the following `.

    • It is strongly recommended to use $(…) instead of `…`.

    • It is important that you use quotes around expansions like "$(…)"

    • There is an additional ; after then


    How do I know? (well, by experience ☺ ) but you can try Shellcheck. Paste the code from the book (after the asterisks) and it will show you the errors listed above plus a "missing shebang". An script without any errors in Shellcheck is this:




    #!/bin/sh
    if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi



    That site works because what was written is "shell code". That is a syntax that works in many shells.



    Some issues that shellcheck doesn't mention are:




    • It is assuming that the date command is the GNU date version. The one with a -d option that accepts tomorrow as a value (busybox has a -d option but doesn't understand tomorrow and BSD has a -d option but is not related to "display" of time).


    • It is better to set the format after all the options date -d tomorrow +'%d'.


    • The cron start time is always in local time, that may make one job start 1 hour earlier of later than an exact day count if the DST (daylight saving time) got set or unset.



    What we got done is a shell script which could be called with cron. We can further modify the script to accept arguments of the program or command to execute, like this (finally, the correct code):



    #!/bin/sh
    [ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
    [ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
    exec "$@"


    Call this script end_of_month.sh and the call in cron is simply:



    00 12 28-31 * * /path/to/script/end_of_month.sh command


    That would run the script end_of_month (which internally will check that the day is the last day of the month) only on the days 28, 29, 30 and 31. There is no need to check for end of month on any other day.



    Make sure the correct path is included. The PATH inside cron will not (not likely) be the same as the user PATH.



    Note that there is one end of month script tested (as indicated below) that could call many other utilities or scripts.



    This will also avoid the additional problem that cron generates with the full command line:




    • Cron splits the command line on any % even if quoted either with ' or " (only a works here). That is a common way in which cron jobs fail.


    You can test if end_of_month.sh script works correctly on some date (without waiting to the end of the month to discover it doesn't work) by testing it with faketime:



    $ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
    Command will be executed....






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 1 '18 at 9:41

























    answered Oct 29 '18 at 9:26









    IsaacIsaac

    12k11852




    12k11852













    • ast-open date (or the date builtin of ksh93 if ksh93 was built as part of ast-open) does support date -d tomorrow +%s or date +%s tomorrow).

      – Stéphane Chazelas
      Oct 29 '18 at 10:02






    • 3





      One could argue that the stuff relating to the scheduling of the script should be separated out into the crontab, while the operational parts remain in the separate script.

      – Kusalananda
      Oct 29 '18 at 10:13











    • One could argue that it is the shell what is doing the scheduling, not cron. @Kusalananda

      – Isaac
      Oct 29 '18 at 10:21






    • 1





      Experience has proven (many times) that it is a lot better to test the script correctly running with faketime than it is to wait till the end of the month to find that the scheduled job didn't work. Like discovering that * * * * * echo "$(date -u +'date %c')" >>~/testfile wont work because one forgot to quote the % (which becomes difficult to debug if only one try every month is posible). @Kusalananda

      – Isaac
      Oct 29 '18 at 10:32






    • 1





      Or one could follow the UNIX-approach and let one tool do one task: Why not have two scripts? You can easily test them in separation, and you can reuse them. Your crontab becomes 00 12 28-31 * * onlastdayofmonth.sh mysuperscript.sh

      – mhutter
      Oct 31 '18 at 15:17



















    • ast-open date (or the date builtin of ksh93 if ksh93 was built as part of ast-open) does support date -d tomorrow +%s or date +%s tomorrow).

      – Stéphane Chazelas
      Oct 29 '18 at 10:02






    • 3





      One could argue that the stuff relating to the scheduling of the script should be separated out into the crontab, while the operational parts remain in the separate script.

      – Kusalananda
      Oct 29 '18 at 10:13











    • One could argue that it is the shell what is doing the scheduling, not cron. @Kusalananda

      – Isaac
      Oct 29 '18 at 10:21






    • 1





      Experience has proven (many times) that it is a lot better to test the script correctly running with faketime than it is to wait till the end of the month to find that the scheduled job didn't work. Like discovering that * * * * * echo "$(date -u +'date %c')" >>~/testfile wont work because one forgot to quote the % (which becomes difficult to debug if only one try every month is posible). @Kusalananda

      – Isaac
      Oct 29 '18 at 10:32






    • 1





      Or one could follow the UNIX-approach and let one tool do one task: Why not have two scripts? You can easily test them in separation, and you can reuse them. Your crontab becomes 00 12 28-31 * * onlastdayofmonth.sh mysuperscript.sh

      – mhutter
      Oct 31 '18 at 15:17

















    ast-open date (or the date builtin of ksh93 if ksh93 was built as part of ast-open) does support date -d tomorrow +%s or date +%s tomorrow).

    – Stéphane Chazelas
    Oct 29 '18 at 10:02





    ast-open date (or the date builtin of ksh93 if ksh93 was built as part of ast-open) does support date -d tomorrow +%s or date +%s tomorrow).

    – Stéphane Chazelas
    Oct 29 '18 at 10:02




    3




    3





    One could argue that the stuff relating to the scheduling of the script should be separated out into the crontab, while the operational parts remain in the separate script.

    – Kusalananda
    Oct 29 '18 at 10:13





    One could argue that the stuff relating to the scheduling of the script should be separated out into the crontab, while the operational parts remain in the separate script.

    – Kusalananda
    Oct 29 '18 at 10:13













    One could argue that it is the shell what is doing the scheduling, not cron. @Kusalananda

    – Isaac
    Oct 29 '18 at 10:21





    One could argue that it is the shell what is doing the scheduling, not cron. @Kusalananda

    – Isaac
    Oct 29 '18 at 10:21




    1




    1





    Experience has proven (many times) that it is a lot better to test the script correctly running with faketime than it is to wait till the end of the month to find that the scheduled job didn't work. Like discovering that * * * * * echo "$(date -u +'date %c')" >>~/testfile wont work because one forgot to quote the % (which becomes difficult to debug if only one try every month is posible). @Kusalananda

    – Isaac
    Oct 29 '18 at 10:32





    Experience has proven (many times) that it is a lot better to test the script correctly running with faketime than it is to wait till the end of the month to find that the scheduled job didn't work. Like discovering that * * * * * echo "$(date -u +'date %c')" >>~/testfile wont work because one forgot to quote the % (which becomes difficult to debug if only one try every month is posible). @Kusalananda

    – Isaac
    Oct 29 '18 at 10:32




    1




    1





    Or one could follow the UNIX-approach and let one tool do one task: Why not have two scripts? You can easily test them in separation, and you can reuse them. Your crontab becomes 00 12 28-31 * * onlastdayofmonth.sh mysuperscript.sh

    – mhutter
    Oct 31 '18 at 15:17





    Or one could follow the UNIX-approach and let one tool do one task: Why not have two scripts? You can easily test them in separation, and you can reuse them. Your crontab becomes 00 12 28-31 * * onlastdayofmonth.sh mysuperscript.sh

    – mhutter
    Oct 31 '18 at 15:17













    8














    Assuming that the syntax errors are fixed, and the command reformulated slightly to be less verbose:



    00 12 28-31 * * [ "$( date -d tomorrow +%d )" != "01" ] || command1


    This runs date +%d -d tomorrow (assuming that it's GNU date that is used) to get tomorrow's date as a two-digit number. If the number isn't 01, then today is not the last day of the month. In that case, the tests succeeds and command1 is not executed. The job is run at noon on the days that could possibly be the last day of the month.



    The original command:



    00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


    This has a few issues:




    • No space after [.

    • A ; directly after then.


    • % is special in cron job specifications and must be escaped as % (see man 5 crontab).

    • There is no final fi at the end that matches up with the if.






    share|improve this answer





















    • 2





      The problem with using [ ... ] && command1 instead of if... is that on days that are not the last day of the month, the cron job will end with a non-zero exit status and that failure may have to be reported. Using [ "$(...)" != 01 ] || command1 is another way to avoid the problem.

      – Stéphane Chazelas
      Oct 29 '18 at 9:24








    • 1





      Another problem with the original code is the ; between then and command1.

      – Stéphane Chazelas
      Oct 29 '18 at 9:26











    • @StéphaneChazelas Another reason why I dislike one-liners, they are difficult to read.

      – Kusalananda
      Oct 29 '18 at 10:10











    • The time difference between consecutive runs of the command might not be an integer amount of (24 hour) days as a DST change will shift the start time of cron.

      – Isaac
      Oct 29 '18 at 12:31






    • 3





      @cat It doesn't matter how you quote, either " or ' (except ), the percent sign % will make cron break the line in two parts. That is one usual way to get cron to fail.

      – Isaac
      Oct 29 '18 at 13:53


















    8














    Assuming that the syntax errors are fixed, and the command reformulated slightly to be less verbose:



    00 12 28-31 * * [ "$( date -d tomorrow +%d )" != "01" ] || command1


    This runs date +%d -d tomorrow (assuming that it's GNU date that is used) to get tomorrow's date as a two-digit number. If the number isn't 01, then today is not the last day of the month. In that case, the tests succeeds and command1 is not executed. The job is run at noon on the days that could possibly be the last day of the month.



    The original command:



    00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


    This has a few issues:




    • No space after [.

    • A ; directly after then.


    • % is special in cron job specifications and must be escaped as % (see man 5 crontab).

    • There is no final fi at the end that matches up with the if.






    share|improve this answer





















    • 2





      The problem with using [ ... ] && command1 instead of if... is that on days that are not the last day of the month, the cron job will end with a non-zero exit status and that failure may have to be reported. Using [ "$(...)" != 01 ] || command1 is another way to avoid the problem.

      – Stéphane Chazelas
      Oct 29 '18 at 9:24








    • 1





      Another problem with the original code is the ; between then and command1.

      – Stéphane Chazelas
      Oct 29 '18 at 9:26











    • @StéphaneChazelas Another reason why I dislike one-liners, they are difficult to read.

      – Kusalananda
      Oct 29 '18 at 10:10











    • The time difference between consecutive runs of the command might not be an integer amount of (24 hour) days as a DST change will shift the start time of cron.

      – Isaac
      Oct 29 '18 at 12:31






    • 3





      @cat It doesn't matter how you quote, either " or ' (except ), the percent sign % will make cron break the line in two parts. That is one usual way to get cron to fail.

      – Isaac
      Oct 29 '18 at 13:53
















    8












    8








    8







    Assuming that the syntax errors are fixed, and the command reformulated slightly to be less verbose:



    00 12 28-31 * * [ "$( date -d tomorrow +%d )" != "01" ] || command1


    This runs date +%d -d tomorrow (assuming that it's GNU date that is used) to get tomorrow's date as a two-digit number. If the number isn't 01, then today is not the last day of the month. In that case, the tests succeeds and command1 is not executed. The job is run at noon on the days that could possibly be the last day of the month.



    The original command:



    00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


    This has a few issues:




    • No space after [.

    • A ; directly after then.


    • % is special in cron job specifications and must be escaped as % (see man 5 crontab).

    • There is no final fi at the end that matches up with the if.






    share|improve this answer















    Assuming that the syntax errors are fixed, and the command reformulated slightly to be less verbose:



    00 12 28-31 * * [ "$( date -d tomorrow +%d )" != "01" ] || command1


    This runs date +%d -d tomorrow (assuming that it's GNU date that is used) to get tomorrow's date as a two-digit number. If the number isn't 01, then today is not the last day of the month. In that case, the tests succeeds and command1 is not executed. The job is run at noon on the days that could possibly be the last day of the month.



    The original command:



    00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1


    This has a few issues:




    • No space after [.

    • A ; directly after then.


    • % is special in cron job specifications and must be escaped as % (see man 5 crontab).

    • There is no final fi at the end that matches up with the if.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Oct 31 '18 at 14:00









    Toby Speight

    5,33011031




    5,33011031










    answered Oct 29 '18 at 8:33









    KusalanandaKusalananda

    132k17253416




    132k17253416








    • 2





      The problem with using [ ... ] && command1 instead of if... is that on days that are not the last day of the month, the cron job will end with a non-zero exit status and that failure may have to be reported. Using [ "$(...)" != 01 ] || command1 is another way to avoid the problem.

      – Stéphane Chazelas
      Oct 29 '18 at 9:24








    • 1





      Another problem with the original code is the ; between then and command1.

      – Stéphane Chazelas
      Oct 29 '18 at 9:26











    • @StéphaneChazelas Another reason why I dislike one-liners, they are difficult to read.

      – Kusalananda
      Oct 29 '18 at 10:10











    • The time difference between consecutive runs of the command might not be an integer amount of (24 hour) days as a DST change will shift the start time of cron.

      – Isaac
      Oct 29 '18 at 12:31






    • 3





      @cat It doesn't matter how you quote, either " or ' (except ), the percent sign % will make cron break the line in two parts. That is one usual way to get cron to fail.

      – Isaac
      Oct 29 '18 at 13:53
















    • 2





      The problem with using [ ... ] && command1 instead of if... is that on days that are not the last day of the month, the cron job will end with a non-zero exit status and that failure may have to be reported. Using [ "$(...)" != 01 ] || command1 is another way to avoid the problem.

      – Stéphane Chazelas
      Oct 29 '18 at 9:24








    • 1





      Another problem with the original code is the ; between then and command1.

      – Stéphane Chazelas
      Oct 29 '18 at 9:26











    • @StéphaneChazelas Another reason why I dislike one-liners, they are difficult to read.

      – Kusalananda
      Oct 29 '18 at 10:10











    • The time difference between consecutive runs of the command might not be an integer amount of (24 hour) days as a DST change will shift the start time of cron.

      – Isaac
      Oct 29 '18 at 12:31






    • 3





      @cat It doesn't matter how you quote, either " or ' (except ), the percent sign % will make cron break the line in two parts. That is one usual way to get cron to fail.

      – Isaac
      Oct 29 '18 at 13:53










    2




    2





    The problem with using [ ... ] && command1 instead of if... is that on days that are not the last day of the month, the cron job will end with a non-zero exit status and that failure may have to be reported. Using [ "$(...)" != 01 ] || command1 is another way to avoid the problem.

    – Stéphane Chazelas
    Oct 29 '18 at 9:24







    The problem with using [ ... ] && command1 instead of if... is that on days that are not the last day of the month, the cron job will end with a non-zero exit status and that failure may have to be reported. Using [ "$(...)" != 01 ] || command1 is another way to avoid the problem.

    – Stéphane Chazelas
    Oct 29 '18 at 9:24






    1




    1





    Another problem with the original code is the ; between then and command1.

    – Stéphane Chazelas
    Oct 29 '18 at 9:26





    Another problem with the original code is the ; between then and command1.

    – Stéphane Chazelas
    Oct 29 '18 at 9:26













    @StéphaneChazelas Another reason why I dislike one-liners, they are difficult to read.

    – Kusalananda
    Oct 29 '18 at 10:10





    @StéphaneChazelas Another reason why I dislike one-liners, they are difficult to read.

    – Kusalananda
    Oct 29 '18 at 10:10













    The time difference between consecutive runs of the command might not be an integer amount of (24 hour) days as a DST change will shift the start time of cron.

    – Isaac
    Oct 29 '18 at 12:31





    The time difference between consecutive runs of the command might not be an integer amount of (24 hour) days as a DST change will shift the start time of cron.

    – Isaac
    Oct 29 '18 at 12:31




    3




    3





    @cat It doesn't matter how you quote, either " or ' (except ), the percent sign % will make cron break the line in two parts. That is one usual way to get cron to fail.

    – Isaac
    Oct 29 '18 at 13:53







    @cat It doesn't matter how you quote, either " or ' (except ), the percent sign % will make cron break the line in two parts. That is one usual way to get cron to fail.

    – Isaac
    Oct 29 '18 at 13:53













    0














    Schedule the last day of every month?
    you can try 0 0 15,L * *





    share








    New contributor




    Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.

























      0














      Schedule the last day of every month?
      you can try 0 0 15,L * *





      share








      New contributor




      Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.























        0












        0








        0







        Schedule the last day of every month?
        you can try 0 0 15,L * *





        share








        New contributor




        Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.










        Schedule the last day of every month?
        you can try 0 0 15,L * *






        share








        New contributor




        Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.








        share


        share






        New contributor




        Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        answered 6 mins ago









        Kylin SkyKylin Sky

        1




        1




        New contributor




        Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.





        New contributor





        Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






        Kylin Sky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Unix & Linux Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f478335%2fschedule-the-last-day-of-every-month%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Loup dans la culture

            How to solve the problem of ntp “Unable to contact time server” from KDE?

            ASUS Zenbook UX433/UX333 — Configure Touchpad-embedded numpad on Linux