Вместо вылавливания ошибок способом, предлагаемым программой 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
··}
··{
····# Преобразует все '*' в 'X', чтобы обойти конфликт с механизмом
····#·· подстановки в командной оболочке. Оригинал сохраняется
····#·· в "sourceline" для включения в сообщение об ошибке.
····sourceline="$min $hour $dom $mon $dow $command"
····min=$(echo "$min" | tr '*' 'X')····# Минуты