Однако формат определения заданий в cron довольно сложен: поля могут определяться как числа, диапазоны, множества и даже содержать мнемонические имена дней недели или месяцев. Хуже того, программа crontab выводит малопонятные сообщения об ошибках, когда встречает огрехи в системном или пользовательском файле с заданиями для планировщика cron.
Например, если допустить опечатку в названии дня недели, crontab выведет примерно такое сообщение об ошибке:
"/tmp/crontab.Dj7Tr4vw6R":9: bad day-of-week
crontab: errors in crontab file, can't install
Фактически в файле, вызывающем эту ошибку, есть вторая ошибка в строке 12, но crontab вынуждает нас пройти долгий путь, чтобы найти ее, из-за некачественной реализации кода, выполняющего проверку на наличие ошибок.
Вместо вылавливания ошибок способом, предлагаемым программой crontab, можно воспользоваться довольно длинным сценарием (в листинге 6.8), который просматривает файлы crontab, проверяет их синтаксис и убеждается, что все значения находятся в допустимых диапазонах. Одна из причин, почему такую проверку стоит реализовать в сценарии командной оболочки, заключается в возможности интерпретировать множества и диапазоны как отдельные значения. То есть для проверки значений, таких как 3-11 или 4, 6 и 9, достаточно проверить допустимость значений 3 и 11 для данного поля в первом случае, и значений 4, 6 и 9 во втором.
Листинг 6.8.Сценарий verifycron
··#!/bin/bash
··# verifycron — проверяет правильность оформления файла crontab.
··#·· За основу принята стандартная нотация cron: min hr dom mon dow CMD,
··#·· где min — числа 0-59, hr — числа 0-23, dom — числа 1-31,
··#·· mon — числа 1-12 (или названия) и dow — числа 0–7 (или названия).
··#·· Поля могут содержать диапазоны (a-e), списки значений, разделенных
··#·· запятыми (a,c,z), или звездочку. Обратите внимание, что форма определения
··#·· диапазона с шагом, допустимая в Vixie cron (например, 2–6/2),
··#·· не поддерживается текущей версией этого сценария.
··validNum()
··{
····# Возвращает 0, если аргумент содержит допустимое целое число,
····#·· и 1 — если нет. Функция принимает само число и максимально
····#·· возможное значение.
····num=$1·· max=$2
····# Для простоты звездочки в полях представляются символами "X",
····#·· то есть любое число в форме "X" по умолчанию считается допустимым.
····if ["$num" = "X"]; then
······return 0
····elif [! -z $(echo $num | sed 's/[[: digit: ]]//g')]; then
······# Отбросить все цифры и проверить остаток. Не пустой? Плохо.
······return 1
····elif [$num −gt $max]; then
······# Числа больше максимального значения недопустимы.
······return 1
····else
······return 0
····fi
··}
··validDay()
··{
····# Возвращает 0, если аргумент содержит допустимое название дня недели;
····#·· 1 — если нет.
····case $(echo $1 | tr '[: upper: ]' '[: lower: ]') in
······sun*|mon*|tue*|wed*|thu*|fri*|sat*) return 0;;
······X) return 0;;··# Особый случай, это замена "*"
······*) return 1
····esac
··}
··validMon()
··{
····# Возвращает 0, если аргумент содержит допустимое название месяца;
····#·· 1 — если нет.
····case $(echo $1 | tr '[: upper: ]' '[: lower: ]') in
······jan*|feb*|mar*|apr*|may|jun*|jul*|aug*) return 0;;
······sep*|oct*|nov*|dec*)····················return 0;;
······X) return 0;; # Особый случай, это замена "*"
······*) return 1········;;
····esac
··}
··fixvars()
··{
····# Преобразует все '*' в 'X', чтобы обойти конфликт с механизмом
····#·· подстановки в командной оболочке. Оригинал сохраняется
····#·· в "sourceline" для включения в сообщение об ошибке.
····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
····# Если имя файла crontab не задано или если он недоступен сценарию
····#·· для чтения, завершить работу с выводом сообщения.
····echo "Usage: $0 usercrontabfile" >&2
····exit 1
··fi
··lines=0·· entries=0·· totalerrors=0
Читать дальше