Crontab job executed every day instead every month - linux

Three days ago I installed the following crontab job with crontab -e:
# execute weekly
0 2 2-31 * 7 sh /home/user/folder/myscript.sh week > /home/user/.crontablog/crontab.log
It's supposed to be executed every sunday night at 2am except the 1st of the month. However it's executed every night at 2am. What's my mistake? I tried 0 instead of 7 for Sunday with the same result :/
Thank you.

Since the format of crontab is like this:
+---------------- minute (0 - 59)
| +------------- hour (0 - 23)
| | +---------- day of month (1 - 31)
| | | +------- month (1 - 12)
| | | | +---- day of week (0 - 6) (Sunday=0 or 7)
| | | | |
* * * * * command to be executed
To execute it every week on Sunday irrespective of the month you need to write it like this:
0 2 * * 7 sh /home/user/folder/myscript.sh week > /home/user/.crontablog/crontab.log

first you can analyze the content of /var/log/cron, grepping for your script to see what is going on.
I suggest you use the following syntax
0 2 * * sun /home/user/folder/myscript.sh week
having given the +x permission on the script file.
Cheers

Now that you respecified your question in the comments you need to do TWO things:
as I said above, use 0 2 * * 7 to run at 2:00am every Sunday; 7 and 0 are equivalent
inside your shell script use an additional test to quietly exit on the first of the month.
That test could be as simple as
test $(date +%d) == "01" && exit
but you could of course also make it a proper if ... with more echo and verbosity.

If you want to run the script every sunday night at 2am, but only if it's not the first day in the month, then you have to use this syntax:
0 2 * * 0 /usr/bin/test $(/bin/date +\%e) -ne 1 && your_command
The test utilliy finally check if it's the first day in month and your_command is only exected if it's not.

Related

Cron a script on every alternate Saturday

I want to schedule some scripts in every alternate Saturday.
I have tried few things like using days of the month but they don't seems to be the best ways to get the alternate days like
10 22 1-7,15-21,29-31 * 6
There should be some better solution to cron the things on alternate Saturdays.
If you want to have special conditions, you generally need to implement the conditions yourself with a test. Below you see the general structure:
# 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
10 22 * * 6 testcmd && command
The command testcmd generally returns exit code 0 if the test is successful or 1 if it fails. If testcmd is successful, it executes command. A few examples that use similar tricks are in the following posts:
Linux crontab for nth Satuday of the month
Is it possible to execute cronjob in every 50 hours?
Cron expression to run every N minutes
how to set cronjob for 2 days?
The easiest way to obtain what you are after is to select the Saturday to be falling on an odd or even week. The test command testcmd would then look like any of the following:
(( $(date "+\%d") \% 14 < 7 )) : group your month in groups of 14 days and select only the first seven of those days. This has issues that two consecutive weeks can be valid. Example, if the 30th of January is a Saturday, then both this Saturday and the next (6th of February) will be valid.
(( $(date "+\%V") \% 2 == 0 )) : group your year in groups of two weeks and select only the first of that week. This has the issue that years with 53 weeks can create two consecutive valid Saturdays on the end of December and the beginning of January. This is not frequent, but it can happen.
The most robust solution is that presented in * how to set cronjob for 2 days? where we change the problem to every 14 days. Based on my answer to that question, you can adapt it to form a little executable that would create you the perfect testcmd:
Replace in the above testcmd with /path/to/testcmd 14 20210731 where the latter is a script that reads;
#!/usr/bin/env bash
# get start time in seconds
start=$(date -d "${2:-#0}" '+%s')
# get current time in seconds
now=$(date '+%s')
# get the amount of days (86400 seconds per day)
days=$(( (now-start) /86400 ))
# set the modulo
modulo=$1
# do the test
(( days >= 0 )) && (( days % modulo == 0))

CRON with AND relationship between mday and wday

I have seen this question which indicates that the relationship between the wday and mday fields of a CRON schedule is an OR relationship. Say for example I want to schedule something for every Friday the 13th.
Rather than the expected result, the CRON
0 0 13 * 5
will give me all Fridays of every month, as well as every 13th of every month.
Is there any way to avoid this behavior and specify an AND relationship? (There seems to be mention of older versions using an AND relationship, however I would prefer to use a single tool with the ability to do both)
I guess, instead of specifying the wday (Friday=5), you'll just have to specify the months where the 13th is a Friday; so, for 2019:
0 0 13 9,12 * : do stuff, but avoid black cats
Or, eternally more elegant, create a small script:
$> cat /home/me/bin/test_friday_13
#!/bin/bash
if [ "$(date +'%A %d')" != "Friday 13" ]
then
exit 1
else
: do stuff, but avoid black cats
exit 0
fi
and make the crontab entry:
0 0 13 * * /home/me/bin/test_friday_13
The script approach has the added benefit that you can run it from the command line. (Note: do not forget to alter the weekday name in the script to reflect your environment.)
The cron-entry you are interested in is:
# 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 0 13 * * [ $(date "+\%u") = "5" ] && command
This will execute the cronjob every 13th of the month. It will compute the day of the week, and test it if it is a Friday (5). If so, it will execute command.
Extended explanation:
If you want to have special conditions, you generally need to implement the conditions yourself with a test. Below you see the general structure:
# 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 0 13 * * /path/to/testcmd && command
The command testcmd generally returns exit code 0 if the test is successful or 1 if it fails. If testcmd is successful, it executes command. A few examples that use similar tricks are in the following posts:
Linux crontab for nth Satuday of the month
Is it possible to execute cronjob in every 50 hours?
Cron expression to run every N minutes
how to set cronjob for 2 days?
The test you want to perform is written in /bin/sh as:
[ $(date "+%u") = 5 ]
Which makes use of the test command (see man test). This is POSIX compliant and will work with any shell that your cron might run in (sh,bash,dash,ksh,zsh). The command date "+%u" returns the weekday from 1 to 7 (Sunday is 7). See man date for more info.
So your cronjob would look like:
0 0 13 * * [ $(date "+\%u") = 5 ] && command
Note that we have to escape the <percent>-character.
A % character in the command, unless escaped with a backslash (\), will be changed into newline characters, and all data after the first % will be sent to the command as standard input.
source: man 5 crontab
Unfortunately, CRON doesn't work the way you want
You can see all available options on below url
https://www.freeformatter.com/cron-expression-generator-quartz.html
So what you can do is the execute the cron on every 13th of the month but don't let the command run when its Friday
0 0 0 13 * ? * mybatchjob.sh
mybatchjob.sh
if [ `date +'%A'` = "Friday" ]; then
echo "Yep its Friday";
else
echo "Not Friday";
fi
This will make sure that the intended program only runs on Friday and the 13th

Linux crontab for nth Satuday of the month

I like to run back up for all weekdays except Saturday.
My crontab entry
30 16 * * 1,2,3,4,5 ./backup.sh
This entry working fine.
Also, I like to take back up on 1st, 3rd Saturday.
If any 5th Sutarday available in a month then the back up should run. What will be the entry for crontab? I am guessing
30 16 1-7, 15-21, 29-31 * 6 ./backup.sh
Am I right?
Am I right?
No you are not correct. The crontab manual states:
Note: The day of a command's execution can be specified in the following two fields day of month, and day of week. If both fields are restricted (i.e., do not contain the "*" character), the command will be run when either field matches the current 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.
So how can we do it?
If you want to determine which Saturday of the month it is, i.e. whether it is the 1st, 2nd or 3rd Saturday of the month, all you have to do is look at the weekday of the Saturday and do the following integer computation:
D=$(date "+%d")
echo $(( (D-1)/7 + 1 ))
This value will return the corresponding number. This does not only work for Saturdays but for any Weekday.
Since the OP wants the cron to work on the 1st, 3rd and potentially the 5th Saturday, it actually states that the cron runs on every odd-numbered Saturday:
D=$(date "+%d")
echo $(( ((D-1)/7 + 1) % 2 ))
Using this as an additional test, allows us to write the cron 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
30 16 * * 6 (( (($(date "+\%d") - 1)/7 + 1) % 2 == 1 )) && command

How to run crontab job every week on Sunday

I'm trying to figure out how to run a crontab job every week on Sunday. I think the following should work, but I'm not sure if I understand correctly. Is the following correct?
5 8 * * 6
Here is an explanation of the crontab format.
# 1. Entry: Minute when the process will be started [0-60]
# 2. Entry: Hour when the process will be started [0-23]
# 3. Entry: Day of the month when the process will be started [1-28/29/30/31]
# 4. Entry: Month of the year when the process will be started [1-12]
# 5. Entry: Weekday when the process will be started [0-6] [0 is Sunday]
#
# all x min = */x
So according to this your 5 8 * * 0 would run 8:05 every Sunday.
To have a cron executed on Sunday you can use either of these:
5 8 * * 0
5 8 * * 7
5 8 * * Sun
Where 5 8 stands for the time of the day when this will happen: 8:05.
In general, if you want to execute something on Sunday, just make sure the 5th column contains either of 0, 7 or Sun. You had 6, so it was running on Saturday.
The format for cronjobs is:
+---------------- minute (0 - 59)
| +------------- hour (0 - 23)
| | +---------- day of month (1 - 31)
| | | +------- month (1 - 12)
| | | | +---- day of week (0 - 6) (Sunday=0 or 7)
| | | | |
* * * * * command to be executed
You can always use crontab.guru as a editor to check your cron expressions.
Following is the format of the crontab file.
{minute} {hour} {day-of-month} {month} {day-of-week} {user} {path-to-shell-script}
So, to run each sunday at midnight (Sunday is 0 usually, 7 in some rare cases) :
0 0 * * 0 root /path_to_command
The crontab website gives the real time results display: https://crontab.guru/#5_8_*_*_0
When specifying your cron values you'll need to make sure that your values fall within the ranges. For instance, some cron's use a 0-7 range for the day of week where both 0 and 7 represent Sunday. We do not(check below).
Seconds: 0-59
Minutes: 0-59
Hours: 0-23
Day of Month: 1-31
Months: 0-11
Day of Week: 0-6
reference: https://github.com/ncb000gt/node-cron
I think you would like this interactive website, which often helps me build complex Crontab directives: https://crontab.guru/
Cron job expression in a human-readable way crontab builder
#weekly work better for me!
example,add the fellowing crontab -e ,it will work in every sunday 0:00 AM
#weekly /root/fd/databasebackup/week.sh >> ~/test.txt
10 * * * Sun
Position 1 for minutes, allowed values are 1-60
position 2 for hours, allowed values are 1-24
position 3 for day of month ,allowed values are 1-31
position 4 for month ,allowed values are 1-12
position 5 for day of week ,allowed values are 1-7 or and the day starts at Monday.
* * * * 0
you can use above cron job to run on every week on sunday, but in addition on what time you want to run this job for that you can follow below concept :
* * * * * Command_to_execute
- � � � -
| | | | |
| | | | +�� Day of week (0�6) (Sunday=0) or Sun, Mon, Tue,...
| | | +���- Month (1�12) or Jan, Feb,...
| | +����-� Day of month (1�31)
| +������� Hour (0�23)
+��������- Minute (0�59)
I'd be really tempted to run using the #weekly keyword if you don't care what time of day this is run. It should run every Sunday, and is definitely more readable.
#weekly some_script.sh

How can I specify time in CRON considering YEAR?

My task is to specify time in CRON considering YEAR field. How can i do it, or do u know any stuff which can help me on my linux server? thx
As indicated in earlier posts, you cannot indicate a year field, it is, however, possible to mimic it:
# 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 0 1 1 * [[ $(date "+\%Y") == 2020 ]] && command1
0 0 1 1 * (( $(date "+\%Y") % 3 == 0 )) && command2
0 0 1 1 * (( $(date "+\%Y") % 3 == 1 )) && command3
Here, command1 will run on the 2020-01-01T00:00:00, command2 will run every 3 years on the first of January at midnight, it will run so on 2019, 2022, 2025, ... . command3 does the same as command2 but has one year offset, i.e. 2020, 2023, 2026, ...
note: don't forget that you have to escape the <percent>-character (%) in your crontab file:
The "sixth" field (the rest of the line) specifies the command to be run. The entire command portion of the line, up to a newline or
a "%" character, will be executed by /bin/sh or by the shell specified in the SHELL variable of the cronfile. A "%" character in the command, unless escaped with a backslash (\), will be changed into newline characters, and all data after the first % will be sent to the command as standard input.
source: man 5 crontab
Crontab (5) file format has no YEAR field. You could try running a cron job #yearly (at 00:00 on New Year's day) which looks at the current year using date(1) and updates the current crontab file to one appropriate for the new year.
Standard cron doesn't support a year field, but it's worth noting that some implementations support an extended crontab format with a sixth year field, such as nnCron. Not every cron is created equal.
var task = cron.schedule('0 0 1 1 *', () => {
console.log('Printing this line 1ST JANUARY OF EVERY YEAR in the terminal');
});
It is work for considering YEAR field..
#mart7ini

Resources