I try to schedule a task in Ubuntu 16.04 using crontab:
45 2 * * 4/2 sh /var/lib/libvirt/images/backups/backup_res.sh
I want it to be executed every other Thursday at 2:45AM.
However, I keep getting bad day-of-week error.
If I remove /2, it works fine.
What could be the problem?
asked Nov 14, 2017 at 7:03
I think the best way is:
45 2 * * Thu expr `date +%s` / 604800 % 2 >/dev/null || sh /var/lib/libvirt/images/backups/backup_res.sh
please see this Q&A
answered Nov 14, 2017 at 8:02
A1GardA1Gard
4,0113 gold badges31 silver badges54 bronze badges
1
In this article, I will explain about the «errors in crontab file, can’t install» error which I was getting while setting up the Crontab. This error is very common and can come up due to various reasons hence it is important to understand the crontab parameters. I will go through multiple scenarios in which this error could occur and how can we resolve this. But before that it is important to understand the crontab parameters through below example.
* * * * * /home/centos/example.sh
| | | | | |
| | | | | Command or Script to execute
| | | | |
| | | | Day of week(0-6)
| | | |
| | | Month(1-12)
| | |
| | Day of Month(1-31)
| |
| Hour(0-23)
|
Min(0-59)
Also Read: 11 Unix/Linux chmod Command examples to Change File Permissions
Scenario 1: When number of crontab field is more than expected
I have been trying to set crontab from User root by running crontab -e
command. After setting up the required fields I tried to save the crontab file multiple times but every time I got below error and it was not allowing me to save the file.
[root@localhost ~]# crontab -e no crontab for root - using an empty one crontab: installing new crontab "/tmp/crontab.gsQNhu":1: bad command errors in crontab file, can't install. Do you want to retry the same edit? y crontab: installing new crontab "/tmp/crontab.gsQNhu":1: bad command errors in crontab file, can't install. Do you want to retry the same edit? y
-e : Edits the current crontab using the editor specified by the VISUAL or EDITOR environment variables. More can be checked on crontab Man Page.
Below is what my crontab file looks like when i got the above error. If you see the below output carefully then you will see an extra star(*)
field due to which above error was showing.
0 3 * * * * /home/centos/example.sh
To resolve this issue i have removed that extra star(*)
mark and then saved the file again. Then i am able to see below output which shows that crontab is successfully saved.
crontab: installing new crontab
Scenario 2: If you forget to mention the Script in Crontab File
Another scenario could be when you forget to mention the Script in Crontab File like the one showing below. Sometimes you might forget to mention the Script file which needs to run as part of cron job and then try to save the file. In those cases also you will get the same "errors in crontab file, can't install"
error.
0 2 * * *
To fix this error you need to edit the crontab file and mention the script file name that needs to be run as part of the cron job.
Scenario 3: You might get «errors in crontab file can’t install bad minute»
I have also seen a scenario where sometimes we might add an extra line like the one mentioned below then if you try to save this crontab file you will get "errors in crontab file can't install bad minute"
error. This is because crontab expects to have a minute value mentioned at the start of every line. In this example, we have used a script called backup.sh
at the start of the Line hence it will throw bad minute error.
0 3 * * * /home/centos/example.sh backup.sh
Scenario 4: You might get «errors in crontab file can’t install bad day-of-week»
I have also seen a scenario where sometimes Linux professionals uses some value in week section which is not expected hence started getting "errors in crontab file can't install bad day-of-week"
error when try to save the file. One of the such instance I have shown below where week section expecting a value between 0 and 6 but instead 9 is mentioned which results in "bad day of the week"
error.
* 4 0 * 9 /home/centos/example.sh
Scenario 5: You might get «errors in crontab file can’t install bad command»
There is another common mistake I have seen Linux Professionals or Beginners often doing is that they will some unexpected command or a command which is not set in $PATH
which results into "errors in crontab file can't install bad command"
error. One such instance I have shown here where jq
command is not there in any of the Linux binary path hence it is not detecting this command. In these cases either you need to provide the complete path of the command or add the command path in $PATH
so that system detects that command.
0/10 * * * * jq
Scenario 6: You might get «bad day-of-month errors in crontab file can’t install»
Finally I have also seen Linux professionals or beginners doing a mistake assuming month section as days of month section and will use any value greater that 12 resulting in "bad day-of-month errors in crontab file can't install"
error. Here you need to be very careful in understanding the difference between days of the month and month of the year. Month of the year accepts value between 1 to 12 whereas days of the month accepts values between 1 to 31.
* * * 15 * /home/centos/example.sh
Popular Recommendations:-
Learn HTML Image Maps(v5) with Best Examples
Easy Steps to Install GCC(C and C++ Compiler) on CentOS 7
C# data types with Best Examples (.NET v4.7)
How to Transfer Files to an AWS EC2 Instance Using WinSCP in 3 Easy Steps
Learn HTML Tables(v5) with Best Examples
How to Install PHP on RedHat/CentOS 7 with Easy Steps
How to Install Ruby on Ubuntu 18.04 with Easy Steps
When I run crontab -e
on my Debian server and add these lines:
# System statistics
*/10 * * * * /usr/lib/sysstat/sa1 1 1 > /dev/null 2>&1
59 23 * * * /usr/lib/sysstat/sa2 -A > /dev/null 2>&1
after save, the crontab complains:
crontab: installing new crontab
"/tmp/crontab.xSbhwZ/crontab":30: bad day-of-week
errors in crontab file, can't install.
This is line 30: */10 * * * * /usr/lib/sysstat/sa1 1 1 > /dev/null 2>&1
. When I comment this line, it’s all fine.
Any thoughts?
asked May 19, 2016 at 16:52
0
Ok, so the problem was «non-breaking» space inserted from OSX (alt+space) between the * instead of regular space – Petr Nagy May 19 ’16 at 17:57
Add that as an answer so that it’s obvious that the question has been answered. – wurtel May 20 ’16 at 7:05
I had the same error,although the bad space was not entered by OSX but by some gremlin. I fixed the problem by pulling the crontab into a file
crontab -l > crontab.txt
And then replacing all the ‘spaces’ in the file with true spaces. I then pulled that text file back into the crontab :
crontab crontab.txt
answered Jan 11, 2018 at 17:55
1
Содержание
- Solved: errors in crontab file, can’t install — Unix & Linux (RHEL/CentOS 7/8)
- errors in crontab file, can’t install
- Scenario 1: When number of crontab field is more than expected
- Scenario 2: If you forget to mention the Script in Crontab File
- Scenario 3: You might get «errors in crontab file can’t install bad minute»
- Scenario 4: You might get «errors in crontab file can’t install bad day-of-week»
- Scenario 5: You might get «errors in crontab file can’t install bad command»
- Scenario 6: You might get «bad day-of-month errors in crontab file can’t install»
- Bad minute crontab error
- Context
- Understand your cron jobs
- What causes this error
- Fixing bad minute errors
- Related Guides
- Подскажите, почему не отрабатывает скрипт в crontab
Solved: errors in crontab file, can’t install — Unix & Linux (RHEL/CentOS 7/8)
Table of Contents
In this article, I will explain about the «errors in crontab file, can’t install» error which I was getting while setting up the Crontab. This error is very common and can come up due to various reasons hence it is important to understand the crontab parameters. I will go through multiple scenarios in which this error could occur and how can we resolve this. But before that it is important to understand the crontab parameters through below example.
errors in crontab file, can’t install
Scenario 1: When number of crontab field is more than expected
I have been trying to set crontab from User root by running crontab -e command. After setting up the required fields I tried to save the crontab file multiple times but every time I got below error and it was not allowing me to save the file.
-e : Edits the current crontab using the editor specified by the VISUAL or EDITOR environment variables. More can be checked on crontab Man Page.
Below is what my crontab file looks like when i got the above error. If you see the below output carefully then you will see an extra star(*) field due to which above error was showing.
To resolve this issue i have removed that extra star(*) mark and then saved the file again. Then i am able to see below output which shows that crontab is successfully saved.
Scenario 2: If you forget to mention the Script in Crontab File
Another scenario could be when you forget to mention the Script in Crontab File like the one showing below. Sometimes you might forget to mention the Script file which needs to run as part of cron job and then try to save the file. In those cases also you will get the same «errors in crontab file, can’t install» error.
To fix this error you need to edit the crontab file and mention the script file name that needs to be run as part of the cron job.
Scenario 3: You might get «errors in crontab file can’t install bad minute»
I have also seen a scenario where sometimes we might add an extra line like the one mentioned below then if you try to save this crontab file you will get «errors in crontab file can’t install bad minute» error. This is because crontab expects to have a minute value mentioned at the start of every line. In this example, we have used a script called backup.sh at the start of the Line hence it will throw bad minute error.
Scenario 4: You might get «errors in crontab file can’t install bad day-of-week»
I have also seen a scenario where sometimes Linux professionals uses some value in week section which is not expected hence started getting «errors in crontab file can’t install bad day-of-week» error when try to save the file. One of the such instance I have shown below where week section expecting a value between 0 and 6 but instead 9 is mentioned which results in «bad day of the week» error.
Scenario 5: You might get «errors in crontab file can’t install bad command»
There is another common mistake I have seen Linux Professionals or Beginners often doing is that they will some unexpected command or a command which is not set in $PATH which results into «errors in crontab file can’t install bad command» error. One such instance I have shown here where jq command is not there in any of the Linux binary path hence it is not detecting this command. In these cases either you need to provide the complete path of the command or add the command path in $PATH so that system detects that command.
Scenario 6: You might get «bad day-of-month errors in crontab file can’t install»
Finally I have also seen Linux professionals or beginners doing a mistake assuming month section as days of month section and will use any value greater that 12 resulting in «bad day-of-month errors in crontab file can’t install» error. Here you need to be very careful in understanding the difference between days of the month and month of the year. Month of the year accepts value between 1 to 12 whereas days of the month accepts values between 1 to 31.
Popular Recommendations:-
Источник
Bad minute crontab error
Context
To understand this error, it’s useful to know two rules about crontab files:
- Every line in your crontab must conform with the cron specification. Other than blank lines and environment variables, every line must be a comment (beginning with # ) or begin with a valid cron job schedule expression.
- The first part of a cron job schedule expression is the minute field.
Understand your cron jobs
What causes this error
When cron reads each line of your crontab, if the line is not a comment it expects it to start with a valid minute expression. If for some reason it doesn’t, it will raise a Bad Minute error.
Fixing bad minute errors
This type of error could have many causes. Here are some troubleshooting steps to identify and fix the problem.
- The error message will commonly indicate the line number that is problematic. Look for the number after a colon, in this example it’s line 11.
- Check for unexpected line breaks in your crontab file. Sometimes you may inadvertently wrap a long line by adding a line break. Cron requires the full schedule and command on a single line.
If every line begins with a cron schedule, check that the first field is accurate. Here are the allowed values for the minute field:
Value | Description |
0-59 | Specific Minute |
* | Every Minute |
, | List of Minutes, e.g. 1,3,5 |
— | Range of Minutes, e.g 1-10 |
/ | Minute step value, e.g. 1/5 |
Tip:To verify and validate your cron expression use Crontab Guru, the free and simple cron expression editor from Cronitor.
Missing newline before EOF
No MTA installed, discarding output
Errors in crontab file, can’t install
Cronitor automatically finds and monitors cron jobs. Complete your setup in minutes.
Источник
Подскажите, почему не отрабатывает скрипт в crontab
Добрый день. Есть один скрипт recycle_clean.sh, он запускается вручную успешно и отрабатывает, но вот в /etc/crontab есть такая запись:
И из него почему-то не отрабатывает этот скрипт. Cron вроде запущен, по /etc/init.d/cron status выдает:
Стало быть крон запущен. Подскажите, почему не отрабатывает?
ls -l /root/scripts/recycle_clean.sh
head /root/scripts/recycle_clean.sh
Выложи содержимое скрипта и syslog в момент запуска кроном.
Вангую отсутствие PATH
и пустую строку в конце не забудьте.
Это группа, в ней доменные пользователи. А так, как вы предложили (* * * * *), он же не будет отрабатывать раз в сутки, или будет?
У меня нет такого лога даже: /var/log/crond.log
и пустую строку в конце не забудьте
старообрядцы в треде
Это группа, в ней доменные пользователи. А так, как вы предложили (* * * * *), он же не будет отрабатывать раз в сутки, или будет?
он будет отрабатывать 1440 раз в сутки. Каждую минуту. Ускоряет поиск ошибки в 1440 раз.
Да, таких групп не бывает в Linux’е.
У меня нет такого лога даже: /var/log/crond.log
а что, починили, да? Я не в курсе, vim подставляет самостоятельно. Но может ТС notepad.exe юзает?
Честно говоря, вообще никогда не встречал этой проблемы в реальности, и всегда думал что crontab -e сам всё валидирует и делает, хоть добавляй, хоть не добавляй
Я по мотивам какого-то треда пару лет назад тестировал это и всё работало при любом варианте
А чтобы раз в сутки нужно оставить как было:
Так как там достаточно много данных перемещает скрипт, каждую минуту не успеет.
Честно говоря, вообще никогда не встречал этой проблемы в реальности, и всегда думал что crontab -e сам всё валидирует и делает, хоть добавляй, хоть не добавляй
crontab -e вызывает EDITOR, а уж что делает $EDITOR — я не знаю. У меня это vim. А вот народ ставил mcedit, и жаловался на эту проблему.
Я по мотивам какого-то треда пару лет назад тестировал это и всё работало при любом варианте
строка должна заканчиваться n, иначе это формально не строка, а мусор. Gcc предупреждает, но компиллит. А вот как сейчас crond — я не знаю.
А чтобы раз в сутки нужно оставить как было:
там можно и это, и любое другое валидное время поставить. Сначала минуты, а потом часы. Лучше ставить на пару минут вперёд, что-бы ждать две минуты.
То есть он не отрабатывает потому что не добавлен в
а после создания такого файла и добавления в него строки, аналогичной таковой в /etc/crontab будет автоматически отрабатывать?
То есть он не отрабатывает потому что не добавлен
не. Ты даже НЕ ЗНАЕШЬ, отрабатывается он, или нет. И если нет — то почему. А в том файле это будет написано.
/var/log/crond.log а после создания такого файла
он сам создастся, с ошибками, которые нужно исправить.
и в /var/log/crond.log появилось:
bash: 59: команда не найдена
задумайся, почему именно 59?
echo нужно в начале?
эту строчку в crontab надо вставлять. В консоль вставляй БЕЗ 59 23 * * * root
Да, это была такая папка, после выполнения скрипта вручную. Я ее удалил и все запустил заново, в логе пусто после этого.
Но все равно он не отрабатывал, так как папка должна создаваться каждый день, а они не создавались. Вот только сегодня вручную запустил — тогда создались.
PATH проверил, все вроде ок в ней.
Спасибо! Она мне не помешает! =) Показал другому одмину — говорит что сам крон не работает, а crontab в порядке. Но вроде показывает:
mv: невозможно переместить «/var/share/data_drive/Disk_S/.recycled/current» в «/var/share/data_drive/Disk_S/.recycled/2014-03-05/current»: Кат$
видимо «каталог существует»
mkdir: невозможно создать каталог «/var/share/data_drive/Disk_S/.recycled/current»: Файл существует
надо проверить, потом создавать
[ -d /var/share/data_drive/Disk_S/.recycled/current ] || mkdir /var/share/data_drive/Disk_S/.recycled/current
у вас в самом скрипте ошибки.
Пусть уволится, он не админ.
Да, это после того как я вручную запустил его (скрипт), каталог создался, и при последующем запуске тоже вручную выдалась такая ошибка, так как каталог был. Я его удалил. Но кронтаб все равно не работает, не понимаю почему.
У нас просто все неспешно. =)
Сейчас содержимое /etc/crontab такое:
Но кронтаб все равно не работает, не понимаю почему.
1. исправьте ошибки в скрипте. Вот что вы мне моск полоскаете? У меня сын первоклашка, у него есть работа над ошибками. У вас какая-то альтернативная школа?
2. заведомо рабочий скрипт пропишите в crontab. Потом читайте логи.
Checking periodic command scheduler. done (running).
и что? Да, работает чего-то. У меня куча таких шедулеров. Тоже работают. Что дальше?
Да вот даже простой скрипт
* * * * * root echo ‘Время: ‘ ; date
КУДА он должен его «выполнять»? Откуда он знает, что вы эмулятор терминала где-то внутри Xorg’а запустили?
Команда выполняется, а результата ты тупо НЕ ВИДИШЬ.
SHELL=/bin/bash же указан
блжад. Это то, ЧТО выполняет. А КУДА?
Обычно по дефолту оно в почту срёт. А у тебя MAILTO=. Что значит — в никуда.
Первый раз вижу, чтобы человек «почти осилил crontab», но в тоже время демонстрировал полное непонимание основ.
А emulek должен получать молоко за вредность.
Вот попробовал на машине с точно таким же шестым дебианом —
И файл создался. А на моем злосчастном серваке — тишина при точно такой же строке.
Я не очень линуксоид по всяким серверным штукам, только как пользователь — ставлю убунты и переустанавливаю убунты.
А emulek’у я очень благодарен.
Первый раз вижу, чтобы человек «почти осилил crontab», но в тоже время демонстрировал полное непонимание основ.
Увы. С тех пор, как изобрели гугл, это обычная ситуация.
А на моем злосчастном серваке — тишина при точно такой же строке.
дык сделай логгирование, как я выше писал. Должно работать.
Да, куда ты прописываешь-то? И как?
Я просто в /etc/crontab прописал ниже под всем, ну команду touch на другой машине с аналогичным дебианом. А вот на этом серваке — тоже добавил. И не отрабатывает. Крон вроде везде одинаковый. Может его переставить? Просто не хотелось бы перезапускать этот сервак. Но просто перезапуск крона не помогает.
думаешь мне интересно, через какую жопу ты делаешь? Нет.
Просто скрипт же отрабатывает если вручную его запускать. Значит не в нем проблема.
Во-первых, если скрипт при повторном запуске без изменения входных данных может обломаться, то это плохой скрипт: http://ru.wikipedia.org/wiki/Идемпотентность
Во-вторых, настройте почтовую подсистему (достаточно взять какой-нибудь nullmailer, чтобы слал через smtp) и настройте перенаправление почты root-а к себе на ящик (ну, или локально складывать, если на машине нет интернета/доступа к какому-нибудь smtp-серверу). Это будет полезно не только для отладки cron, но и для получения информации по многим системным событиям (smartd руту пишет, например, когда на дисках происходит что-то нехорошее).
В-третьих, чтобы закончить бессмысленные аргументы на тему того, что «cron не работает», посмотрите /var/log/syslog. Там будут строчки типа:
Найдите строчки, которые соответствуют запуску задания с вашим скриптом (они там будут, даже если скрипт обломается).
Источник
This is a common error
Context
You will encounter this error when you attempt to create or update
a crontab file that contains a syntax error.
What causes this error
Crontab files, while very simple, have a precise specification. Among other things, a crontab must:
- Start with a valid cron schedule, environment variable or comment on each line
- Contain an executable expression after the schedule
- End with a newline
- Include a username after the schedule for system-wide crontab files
When any syntax error occurs, cron will return the message errors in crontab file can't install
.
Fixing Errors in crontab file can’t install
This error message often includes a more specific problem that you can address, for example:
- Bad Minute Crontab Error
- Missing Newline Before EOF Error
If you are still stuck, review your local documentation for further guidance on crontab format. You can do this from your command line by running man 5 crontab
Related Guides
Cronitor automatically finds and monitors cron jobs. Complete your setup in minutes.
Get Started Free
Hi,
I am getting this error while editing the crontab?
crontab: installing new crontab
«/tmp/crontab.XXXXePsNSJ»:2: bad day-of-week
errors in crontab file, can’t install.
Do you want to retry the same edit?
The crontab value is a below;
### recording mixing for Asterisk run every 5 minutes
1,6,11,16,21,26,31,36,41,46,51,56 * * *
1,2,3,4,5,6 /usr/share/astguiclient/AST_CRON_mix_recordings_BASIC.pl
### keepalive script for astguiclient processes
* * * * * /usr/share/astguiclient/ADMIN_keepalive_ALL.pl
### kill Hangup script for Asterisk updaters
* * * * * /usr/share/astguiclient/AST_manager_kill_hung_congested.pl
### updater for voicemail
* * * * * /usr/share/astguiclient/AST_vm_update.pl
### updater for conference validator
* * * * * /usr/share/astguiclient/AST_conf_update.pl
### flush queue DB table every hour for entries older than 1 hour
11 * * * * /usr/share/astguiclient/AST_flush_DBqueue.pl -q
### fix the vicidial_agent_log once every hour
33 * * * * /usr/share/astguiclient/AST_cleanup_agent_log.pl
### updater for VICIDIAL hopper
* * * * * /usr/share/astguiclient/AST_VDhopper.pl -q
### adjust the GMT offset for the leads in the vicidial_list table
1 1 * * * /usr/share/astguiclient/ADMIN_adjust_GMTnow_on_leads.pl —
debug —postal-code-gmt
### reset several temporary-info tables in the database
2 1 * * * /usr/share/astguiclient/AST_reset_mysql_vars.pl
### optimize the database tables within the asterisk database
3 1 * * * /usr/share/astguiclient/AST_DB_optimize.pl
## adjust time on the server with ntp
30 * * * * /usr/local/bin/ntpdate -u 18.145.0.30 2>/dev/null 1>&2
### VICIDIAL agent time log weekly summary report generation
2 0 * * 0 /usr/share/astguiclient/AST_agent_week.pl
Your help is highly appreciated.
#53 Validating User crontab Entries
One of the most helpful facilities in Unix is cron , with its ability to schedule jobs at arbitrary times in the future, recurring every minute, every few hours, monthly, or annually. Every good system administrator has a Swiss army knife of scripts running from the crontab file.
However, the format for entering cron specifications is a bit tricky, and the cron fields have numeric values, ranges, sets, and even mnemonic names for days of the week or months. What’s worse is that the crontab program generates insufficient error messages when scanning in a cron file that might be incorrectly structured.
For example, specify a day of the week with a typo, and crontab reports
"/tmp/crontab.Dj7Tr4vw6R":9: bad day-of-week crontab: errors in crontab file, can't install
In fact, there’s a second error in the sample input file, on line 12, but crontab is going to force us to take the long way around to find it in the script because of its poor error-checking code.
Instead of doing it crontab ‘s way, a somewhat lengthy shell script can step through the crontab files, checking the syntax and ensuring that values are within reasonable ranges. One of the reasons that this validation is possible in a shell script is that sets and ranges can be treated as individual values. So to test whether 3 “11 or 4,6,9 are acceptable values for a field, simply test 3 and 11 in the former case, and 4, 6, and 9 in the latter.
The Code
#!/bin/sh # verifycron - Checks a crontab file to ensure that it's # formatted properly. Expects standard cron notation of # min hr dom mon dow CMD # where min is 0-59, hr is 0-23, dom is 1-31, mon is 1-12 (or names) # and dow is 0-7 (or names). Fields can be ranges (a-e), lists # separated by commas (a,c,z), or an asterisk. Note that the step # value notation of Vixie cron (e.g., 2-6/2) is not supported by this script. validNum() { # Return 0 if valid, 1 if not. Specify number and maxvalue as args num= max= if [ "$num" = "X" ] ; then return 0 elif [ ! -s $(echo $num sed 's/[[:digit:]]//g') ] ; then return 1 elif [ $num -lt 0 -o $num -gt $max ] ; then return 1 else return 0 fi } validDay() { # Return 0 if a valid dayname, 1 otherwise case $(echo tr '[:upper:]' '[:lower:]') in sun*mon*tue*wed*thu*fri*sat*) return 0 ;; X) return 0 ;; # special case - it's an "*" *) return 1 esac } validMon() { # Return 0 if a valid month name, 1 otherwise case $(echo tr '[:upper:]' '[:lower:]') in jan*feb*mar*apr*mayjun*jul*aug*) return 0 ;; sep*oct*nov*dec*) return 0 ;; X) return 0 ;; # special case, it's an "*" *) return 1 ;; esac } fixvars() { # Translate all '*' into 'X' to bypass shell expansion hassles # Save original input as "sourceline" for error messages sourceline="$min $hour $dom $mon $dow $command" min=$(echo "$min" tr '*' 'X') hour=$(echo "$hour" tr '*' 'X') dom=$(echo "$dom" tr '*' 'X') mon=$(echo "$mon" tr '*' 'X') dow=$(echo "$dow" tr '*' 'X') } if [ $# -ne 1 ] [ ! -r ] ; then echo "Usage:#!/bin/sh # verifycron - Checks a crontab file to ensure that it's # formatted properly. Expects standard cron notation of # min hr dom mon dow CMD # where min is 0-59, hr is 0-23, dom is 1-31, mon is 1-12 (or names) # and dow is 0-7 (or names). Fields can be ranges (a-e), lists # separated by commas (a,c,z), or an asterisk. Note that the step # value notation of Vixie cron (e.g., 2-6/2) is not supported by this script. validNum() { # Return 0 if valid, 1 if not. Specify number and maxvalue as args num=$1 max=$2 if [ "$num" = "X" ] ; then return 0 elif [ ! -s $(echo $num sed 's/[[:digit:]]//g') ] ; then return 1 elif [ $num -lt 0 -o $num -gt $max ] ; then return 1 else return 0 fi } validDay() { # Return 0 if a valid dayname, 1 otherwise case $(echo $1 tr '[:upper:]' '[:lower:]') in sun*mon*tue*wed*thu*fri*sat*) return 0 ;; X) return 0 ;; # special case - it's an "*" *) return 1 esac } validMon() { # Return 0 if a valid month name , 1 otherwise case $(echo $1 tr '[:upper:]' '[:lower:]') in jan*feb*mar*apr*mayjun*jul*aug*) return 0 ;; sep*oct*nov*dec*) return 0 ;; X) return 0 ;; # special case, it's an "*" *) return 1 ;; esac } fixvars() { # Translate all '*' into 'X' to bypass shell expansion hassles # Save original input as "sourceline" for error messages sourceline="$min $hour $dom $mon $dow $command" min=$(echo "$min" tr '*' 'X') hour=$(echo "$hour" tr '*' 'X') dom=$(echo "$dom" tr '*' 'X') mon=$(echo "$mon" tr '*' 'X') dow=$(echo "$dow" tr '*' 'X') } if [ $# -ne 1 ] [ ! -r $1 ] ; then echo "Usage: $0 usercrontabfile" >&2; exit 1 fi lines=0 entries=0 totalerrors=0 while read min hour dom mon dow command do lines="$(($lines + 1))" errors=0 if [ -z "$min" -o "${min%${min#?}}" = "#" ] ; then continue # nothing to check elif [ ! -z $(echo ${min%${min#?}} sed 's/[[:digit:]]//') ] ; then continue # first char not digit: skip! fi entries="$(($entries + 1))" fixvars #### Broken into fields, all '*' replaced with 'X' # Minute check for minslice in $(echo "$min" sed 's/[,-]/ /g') ; do if ! validNum $minslice 60 ; then echo "Line ${lines}: Invalid minute value "$minslice"" errors=1 fi done # Hour check for hrslice in $(echo "$hour" sed 's/[,-]/ /g') ; do if ! validNum $hrslice 24 ; then echo "Line ${lines}: Invalid hour value "$hrslice"" errors=1 fi done # Day of month check for domslice in $(echo $dom sed 's/[,-]/ /g') ; do if ! validNum $domslice 31 ; then echo "Line ${lines}: Invalid day of month value "$domslice"" errors=1 fi done # Month check for monslice in $(echo "$mon" sed 's/[,-]/ /g') ; do if ! validNum $monslice 12 ; then if ! validMon "$monslice" ; then echo "Line ${lines}: Invalid month value "$monslice"" errors=1 fi fi done # Day of week check for dowslice in $(echo "$dow" sed 's/[,-]/ /g') ; do if ! validNum $dowslice 31 ; then if ! validDay $dowslice ; then echo "Line ${lines}: Invalid day of week value "$dowslice"" errors=1 fi fi done if [ $errors -gt 0 ] ; then echo ">>>> ${lines}: $sourceline" echo "" totalerrors="$(( $totalerrors + 1 ))" fi done < $1 echo "Done. Found $totalerrors errors in $entries crontab entries." exit 0usercrontabfile" >&2; exit 1 fi lines=0 entries=0 totalerrors=0 while read min hour dom mon dow command do lines="$(($lines + 1))" errors=0 if [ -z "$min" -o "${min%${min#?}}" = "#" ] ; then continue # nothing to check elif [ ! -z $(echo ${min%${min#?}} sed 's/[[:digit:]]//') ] ; then continue # first char not digit: skip! fi entries="$(($entries + 1))" fixvars #### Broken into fields, all '*' replaced with 'X' # Minute check for minslice in $(echo "$min" sed 's/[,-]/ /g') ; do if ! validNum $minslice 60 ; then echo "Line ${lines}: Invalid minute value "$minslice"" errors=1 fi done # Hour check for hrslice in $(echo "$hour" sed 's/[,-]/ /g') ; do if ! validNum $hrslice 24 ; then echo "Line ${lines}: Invalid hour value "$hrslice"" errors=1 fi done # Day of month check for domslice in $(echo $dom sed 's/[,-]/ /g') ; do if ! validNum $domslice 31 ; then echo "Line ${lines}: Invalid day of month value "$domslice"" errors=1 fi done # Month check for monslice in $(echo "$mon" sed 's/[,-]/ /g') ; do if ! validNum $monslice 12 ; then if ! validMon "$monslice" ; then echo "Line ${lines}: Invalid month value "$monslice"" errors=1 fi fi done # Day of week check for dowslice in $(echo "$dow" sed 's/[,-]/ /g') ; do if ! validNum $dowslice 31 ; then if ! validDay $dowslice ; then echo "Line ${lines}: Invalid day of week value "$dowslice"" errors=1 fi fi done if [ $errors -gt 0 ] ; then echo ">>>> ${lines}: $sourceline" echo "" totalerrors="$(( $totalerrors + 1 ))" fi done < echo "Done. Found $totalerrors errors in $entries crontab entries." exit 0
How It Works
The greatest challenge in getting this script to work is sidestepping problems with the shell wanting to expand the field value * . An asterisk is perfectly acceptable in a cron entry, and indeed is quite common, but give one to a backtick command and it’ll expand to the files in the current directory ” definitely not a desired result. Rather than puzzle through the combination of single and double quotes necessary to solve this problem, it proves quite a bit simpler to replace each asterisk with an X, which is what the fixvars function accomplishes.
Also worthy of note is the simple solution to processing comma-and dash-separated lists of values. The punctuation is simply replaced with spaces, and each value is tested as if it were a stand-alone numeric value. That’s what the $() sequence does in the for loops :
$(echo "$dow" sed 's/[,-]/ /g')
With this in the code, it’s then simple to step through all numeric values, ensuring that each and every one is valid and within the range for that specific crontab field parameter.
Running the Script
This script is easy to run: Just specify the name of a crontab file as its only argument. To work with an existing crontab file, do this:
$ crontab -l > my.crontab $ verifycron my.crontab $ rm my.crontab
The Results
Using a sample crontab file that has two errors and lots of comments, the script produced these results:
$ verifycron sample.crontab Line 10: Invalid day of week value "Mou" >>>> 10: 06 22 * * Mou /home/ACeSystem/bin/del_old_ACinventories.pl Line 12: Invalid minute value "99" >>>> 12: 99 22 * * 1-3,6 /home/ACeSystem/bin/dump_cust_part_no.pl Done. Found 2 errors in 17 crontab entries.
The sample crontab file with the two errors, along with all the shell scripts explored in this book, are available at the official Wicked Cool Shell Scripts website, at http://www.intuitive.com/wicked/
Hacking the Script
Two enhancements would be potentially worth adding to this script. Validating the compatibility of month and day combinations would ensure that users don’t schedule a cron job to run on, for example, 31 February, which will never happen. It could also be useful to check that the command being invoked can be found, but that would entail parsing and processing a PATH variable (i.e., a list of directories within which to look for commands specified in the script), which can be set explicitly within a crontab file. That could be quite tricky. . . .