Планировщик задач cron(8) существует с 7 версии Unix, а его синтаксис crontab(5) знаком даже тем, кто нечасто сталкивается с системным администрированием Unix. Это стандартизированный, довольно гибкий, простой в настройке и надёжно работающий планировщик, которому пользователи и системные пакеты доверяют управление важными задачами. Материалом о лучших практиках работы с cron делимся к старту курса по Fullstack-разработке на Python.


У простоты cron(8), как и многих старых Unix-инструментов, есть недочёт: программа полагается на то, что пользователь хотя бы примерно знает, как всё работает, и в состоянии правильно реализовать в нём какую-то проверку безопасности.

По сути, единственное, что делает планировщик, — это пытается запустить задачу в определённое время и прислать результат на электронную почту. Для простых и незначительных задач пользователей таких возможностей вполне достаточно.

Но для более важных системных задач стоит обернуть вокруг cron(8) и вызываемых им задач дополнительную инфраструктуру. Если вам хочется отслеживать выполняемые задачи, то существует несколько способов повысить надёжность работы с cron(8).

Применяйте принцип минимальной привилегии

Шестой столбец в системном файле crontab(5) — это имя пользователя, который должен запускать задачу:

0 * * * *  root  cron-task

По возможности вы должны запускать задачу от имени пользователя, привилегий которого должно хватать только на это действие и никакое другое. Иногда имеет смысл создать отдельного системного пользователя только для запуска запланированных задач, связанных с вашим приложением.

0 * * * *  myappcron  cron-task

Это делается не только из соображений безопасности (хотя их тоже следует учитывать); данная мера защищает вас от таких неприятностей, как ошибки сценариев, которые пытаются удалить все системные директории.

Также старайтесь не запускать задачи с системами баз данных (как, например, MySQL) через пользователя root с правами администратора. Лучше сделайте это под другим пользователем…

Или даже создайте специального пользователя с ограниченными разрешениями и уникальным случайным паролем, который будет храниться в защищённом файле ~/.my.cnf. К примеру, для задачи резервного копирования MySQL требуется всего лишь несколько разрешений: SELECT, SHOW VIEW и LOCK TABLES.

Конечно же, иногда действительно нужно заходить под root. В особо конфиденциальных случаях можно даже воспользоваться sudo(8) с соответствующими опциями NOPASSWD, чтобы назначенный пользователь мог запускать только определённые задачи под root и ничего более.

Тестируйте задачи

Перед тем как добавить задачу в файл crontab(5), необходимо протестировать её в командной строке в роли пользователя, который будет запускать задачу, и с теми же параметрами среды. Если вы будете запускать задачу как root, то воспользуйтесь чем-то вроде su или sudo -i , чтобы сначала получить root-оболочку с ожидаемой средой пользователя:

$ sudo -i -u cronuser
$ cron-task

Как только задача «отработала» в командной строке, добавьте её в файл crontab(5). Измените настройки времени так, чтобы задача запустилась через несколько минут, а затем просмотрите /var/log/syslog с помощью команды tail -f и убедитесь, что задача запускается без ошибок и выполняется правильно:

May  7 13:30:01 yourhost CRON[20249]: (you) CMD (cron-task)

Поначалу такая процедура кажется педантичной, но очень скоро становится привычной и избавляет от множества хлопот, ведь так просто предположить что-то, что есть в вашей среде, но отсутствует в среде использования cron(8).

А ещё это необходимая проверка того, что ваш файл crontab(5) имеет правильную структуру — некоторые реализации cron(8) не загружают целый файл, если одна из строк имеет неправильный формат.

При необходимости в начале файла вы можете задать произвольные переменные среды для задач:

MYVAR=myvalue

0 * * * *  you  cron-task

Не отказывайтесь от вывода ошибок или полезных результатов выполнения

Скорее всего, вы уже встречали руководства в сети, в которых для того чтобы crontab(5) не рассылал стандартные результаты и/или типовые письма с ошибками каждые 5 минут, в конце описания задания добавляются операторы перенаправления оболочки. Этот кустарный способ очень популярен для запуска задач по веб-разработке путём автоматизации запроса к URL через curl(1) или wget(1):

*/5 * * *  root  curl https://example.com/cron.php >/dev/null 2>&1

Полное игнорирование результатов выполнения — это всегда плохо. Ведь если вам выдают только нужные результаты или ошибки и у вас нет других задач или средств мониторинга выполнения заданий, то вы не заметите проблем (и не узнаете, в чём они заключаются).

В случае с curl(1) столько всего могло пойти не так, а вы заметили бы это слишком поздно:

  • Скрипт мог сломаться и вернуть 500 ошибок.

  • URL задачи cron.php мог измениться, а кто-то забыл добавить перенаправление HTTP 301.

  • Но даже с настроенным редиректом HTTP 301 вы не сможете на него перейти, если не воспользуетесь в curl(1) командами -L или --location.

  • Клиент мог попасть в чёрный список, на запросе мог сработать брандмауэр… его могли заблокировать автоматические или ручные процессы, которые ошибочно пометили запрос как спам.

  • При несоответствии шифра или протокола в HTTPS могло сломаться подключение.

Автор встречал всё из вышеперечисленного, и даже очень часто.

Лучше потратить какое-то время на чтение справочной страницы вызываемой задачи и поискать, как правильно управлять результатами выполнения, чтобы получать действительно нужные вам данные. Например, в случае с curl(1) я заметил, что хорошо работает следующая формула:

curl -fLsS -o /dev/null http://example.com/
  • -f: если код ответа HTTP — это ошибка, то сгенерировать сообщение об ошибке, а не страницу 404.

  • -L: если указано перенаправление HTTP 301, то попробовать перейти на него.

  • -sS: не показывать индикатор выполнения (-S также не позволяет -s блокировать сообщения об ошибках).

  • -o /dev/null: отправить стандартный результат выполнения (фактически возвращённую страницу) в /dev/null.

Таким образом, в соответствии со старой Unix-философией Правила тишины ваш запрос curl(1) будет молчать, пока всё работает как надо.

Вы можете не согласиться с некоторыми из перечисленных вариантов; можете посчитать, что, например, нужно сохранять полный вывод возвращённой страницы или выдавать ошибку, а не тихо переходить на редирект 301, или же вообще предпочтёте пользоваться wget(1).

Суть в том, что вы пробуете разобраться, чего и при каких обстоятельствах ждать от вызываемой программы, а вместо бездумного удаления всех результатов и (что ещё хуже) ошибок пытаетесь как можно лучше подстроить программу под ваши требования. Поработайте с законом Мерфи; исходите из того, что всё, что могло пойти не так, со временем пойдёт не так.

Отправляйте результат выполнения в полезное место

Ещё одна распространённая ошибка — не прописывать вверху файла crontab(5) правильный MAILTO , куда будут отправляться все ошибки и результаты выполнения задач.

Для отправки своих сообщений cron(8) использует реализацию системной почты, а стандартные конфигурации для почтовых агентов чаще всего отправляют сообщение в файл mbox в /var/mail/$USER, который могут никогда и не читать, что сводит на нет всю концепцию рассылки результатов и ошибок.

Но это легко исправить. Сделайте так, чтобы сообщения отправлялись на адрес, который вы действительно проверяете с сервера… возможно, даже с помощью mail(1):

$ printf '%s\n' 'Test message' | mail -s 'Test subject' you@example.com

Как только вы проверили корректную настройку почтового агента и убедились, что на почтовый ящик доставляются письма, пропишите этот адрес в переменной MAILTO в начале файла:

MAILTO=you@example.com

0 * * * *    you  cron-task-1
*/5 * * * *  you  cron-task-2

Если же вы не хотите получать результаты выполнения задачи на электронную почту, то имеется и другой способ. С помощью такого инструмента, как logger(1), вы можете отправлять эти данные в syslog:

0 * * * *   you  cron-task | logger -it cron-task

Ещё можно настроить псевдонимы в системе, чтобы перенаправлять ваши системные письма на тот адрес, которым пользуетесь. Для постфикса воспользуйтесь файлом aliases(5).

Иногда я пользуюсь этим способом, если задача может завершиться несколькими строками выходных значений, которые будут полезны для последующего анализа, но обычные результаты stderr отправляю через MAILTO. Если вы не хотите пользоваться syslog (возможно, из-за большого объёма и/или частоты отправляемых данных), то всегда можно настроить файл журнала /var/log/cron-task.log… но не забудьте добавить для этого правило logrotate(8)!

Добавляйте задачи в собственный файл сценария оболочки

В идеале команды в определениях crontab(5) должны состоять из нескольких слов, а сам файл содержать 1–2 команды. Если команда выполняется за экраном, то, скорее всего, она слишком длинная для crontab(5), поэтому вам следует добавить её в собственный сценарий. Эта идея особенно хороша, если для своих команд вы хотите эффективно пользоваться возможностями bash или других оболочек (помимо POSIX/Bourne /bin/sh)… или даже языком сценариев (например, Awk или Perl). Для разбора команд cron(8) по умолчанию использует системную реализацию /bin/sh.

Файлы crontab(5) не допускают многострочных команд и имеют ряд других недостатков (например, знаки процента (%) нужно экранировать обратной косой чертой). Поэтому хранить как можно больше конфигураций вне crontab(5) — это, в общем-то, и неплохая идея.

Если вы запускаете задачи cron(8) от имени несистемного пользователя и не можете добавить сценарии в системный bindir в виде /usr/local/bin, то правильнее всего будет прописать свой собственный скрипт и добавить ссылку на него в PATH. Я предпочитаю ~/.local/bin, но встречал ссылки и на ~/bin. Сохраните сценарий в ~/.local/bin/cron-task, сделайте его исполняемым с помощью chmod +x и включите эту директорию в определение среды PATH в верхушке файла:

PATH=/home/you/.local/bin:/usr/local/bin:/usr/bin:/bin
MAILTO=you@example.com

0 * * * *  you  cron-task

Собственная директория с пользовательскими сценариями под личные нужды имеет массу преимуществ, но это тема для другой статьи.

Избегайте /etc/crontab

Если ваша реализация cron(8) это поддерживает, то вместо бесконечно длинного файла /etc/crontab попробуйте вынести задачи в отдельный файл /etc/cron.d:

$ ls /etc/cron.d
system-a
system-b
raid-maint

Такая структура позволит логически сгруппировать файлы конфигураций так, что вы (и другие администраторы) сможете быстрее находить нужные задачи. Кроме того, вы сможете сделать какие-то файлы доступными для редактирования только определённым пользователям, чтобы снизить вероятность конфликтов изменений. Здесь, кстати, пригодится и sudoedit(8).

Ещё один плюс в том, что он лучше работает с контролем версий. Так что, если собирается изрядное количество таких файлов задач либо они обновляются чаще раза за пару месяцев, то я запускаю Git-репозиторий для их отслеживания:

$ cd /etc/cron.d
$ sudo git init
$ sudo git add --all
$ sudo git commit -m "First commit"

Если вы редактируете файл crontab(5) для задач только определённого пользователя, то воспользуйтесь инструментом crontab(1). Для изменения crontab(5) напечатайте crontab -e. Так ваш $EDITOR сможет внести изменения во временный файл, который будет установлен при выходе. Файлы сохранятся в специально выделенной директории, в моей системе она называется /var/spool/cron/crontabs.

В системах, которые я поддерживал, готовый шаблон /etc/crontab мог никогда не меняться. Это нормально.

Добавьте время ожидания

Обычно cron(8) разрешает задаче выполняться бесконечно, так что если вам этого не нужно, то следует прописать время ожидания (тайм-аут) в опциях вызываемой программы либо включить его в сценарий. Если в самой команде нужных параметров нет, то одним из возможных способов реализации станет обёртка команды timeout(1) в coreutils:

0 * * * *  you  timeout 10s cron-task

В Википедии Грега (Greg’s Wiki) можно найти целый ряд дополнительных предложений по реализации тайм-аутов.

Избегайте переполнения — включите блокировку файла

cron(8) запускает новый процесс вне зависимости от того, завершились предыдущие запуски или нет. Так что если вы хотите избежать блокировки задач с длительным временем выполнения, то в GNU/Linux можно воспользоваться обёрткой flock(1) для системного вызова flock(2) — она настроит особый файл блокировки, который предотвращает параллельное выполнение задач в более чем одном экземпляре cron.

0 * * * *  you  flock -nx /var/lock/cron-task cron-task

В Википедии Грега (Greg’s Wiki) можно найти подробное обсуждение типовой блокировки файла для сценариев, включая важные нюансы о «развёртывании собственных файлов», если flock(1) недоступен.

Если вам важно запускать какие-то действия в определённом порядке, то подумайте, нужно ли разводить их в отдельные задачи? Возможно, если собрать задачи в один сценарий оболочки, вам будет проще организовать их последовательное выполнение.

Используйте статусы выхода с пользой

Если ваша задача в cron(8) (или команды внутри её сценария) завершается ненулевыми значениями, то лучше запустить команды, которые смогли бы правильно обработать ошибки. Например, очистить соответствующие ресурсы и отправить информацию о текущем статусе задания в средства мониторинга. Если вы пользуетесь Nagios Core или его вариациями, то присмотритесь к send_nsca — он может передавать пассивную проверку статуса задачи на сервер мониторинга. Я написал простой сценарий nscaw, который делает это за меня:

0 * * * *  you  nscaw CRON_TASK -- cron-task

Рассмотрите альтернативы cron(8)

Если ваша машина работает не круглые сутки, а задачу не нужно запускать в опредёленное время (допустим, она запускается раз в день или раз в неделю), то лучше установите anacron и перекиньте сценарии в /etc соответствующих директорий cron.hourly, cron.daily, cron.monthly и cron.weekly. Обратите внимание, что в /etc/crontab по умолчанию для Debian и Ubuntu GNU/Linux есть хуки для запуска, но задачи запускаются, только если не установлен anacron(8).

Если вы используете cron(8), чтобы «спросить» директорию об изменениях и запустить сценарий только при наличии каких-то изменений, то в GNU/Linux лучше прописать демона на основе inotifywait(1).

И, наконец, если вам нужен больший контроль над тем, когда и как запускаются задачи, а возможности cron(8) в этом плане вас не устраивают, то, возможно, стоит написать демона, который будет последовательно работать на сервере и разветвлять процессы для своей задачи.

Например, это позволит запускать задачу чаще одного раза в минуту. Не зацикливайтесь на cron(8) как на единственном варианте для асинхронного управления задачами!

А мы поможем вам прокачать навыки или освоить профессию в IT, актуальную в любое время.

Выбрать другую востребованную профессию.

Краткий каталог курсов и профессий

Комментарии (42)


  1. unsignedchar
    20.03.2022 00:10
    +6

    Я бы ещё добавил, всегда использовать crontab -e и не редактировать файлы cron напрямую.

    А для одноразовых задач использовать at.


    1. catanfa
      20.03.2022 02:01

      а в чём преимущества редактирования через `crontab -e`?


      1. kornerz
        20.03.2022 08:51
        +5

        проверка синтаксиса при выходе из редактора, с предложением исправить ошибки (аналогично visudo, vipw)


      1. 4lex
        20.03.2022 11:00
        +4

        Возможность опечататься и написать "crontab -r" - и на старых системах снести cron-овский файлик к чертям =)

        Ну, а если серьезно тоже редактирую через crontab -e


        1. Hes
          21.03.2022 23:10

          Для простого чтения (перед редактированием) можно использовать

          crontab -l. Если вдруг введете crontab -r


    1. polar_yogi
      20.03.2022 22:31
      +2

      Cтоило бы еще добавить, например,

      что существует системный файл crontab, о котором писалось, и пользовательские файлы (/var/spool/cron/crontabs) которые не предназначены для редактирования вручную, и именно для них придуман crontab -e, чтобы, в частности, отправлять сигнал основному процессу перечитать кронтабы; как обычному пользователю редактировать /etc/crontab тоже как-то осталось за кадром

      что путь по-умолчанию устанавливается в /bin:/usr/bin ( /sbin отсутствует ); ну и вообще про работу с переменными окружения

      про cron.allow / cron.deny


  1. denzill
    20.03.2022 02:00
    +5

    PATH=/home/you/.local/bin:/usr/local/bin:/usr/bin:/bin

    а потом кто-нибудь положит в /home/you/.local/bin файл с именем ls и интересным содержимым, и заимеет доступ к серверу (при неблагоприятных обстоятельствах).

    Такие пути надо добавлять в конец.


  1. aik
    20.03.2022 03:05
    +1

    А ещё без необходимости в системный крон лучше не лазить. У юзера свой crontab имеется. И всякие wget лучше там прописывать, как мне кажется.


  1. kik_krsk
    20.03.2022 03:35
    +5

    А не лучше в 22году использовать таймеры systemd?


    1. mavir
      20.03.2022 09:24
      +2

      Синтаксис у cron, намного проще. Добавить строчку в cron намного проще, чем в таймеры. Мало кто без Гугла сможет создать новый таймер. Таймеры удобно использовать для некоторых специфических задач, например, случайная задержка при выполнении задания


      1. maxx_s
        20.03.2022 12:10

        Как раз хотел добавить что крон запускает все задачи время которых настало одновременно, поэтому, если их много и это допустимо, то не лишним будет вставить перед запуском sleep на какое-то время, случайное, или раскидать вручную, иначе можно упереться в диск или проц, например.

        Сгладить или уменьшить пиковую загрузку ресурсов ещё поможет запуск с nice.


  1. lorc
    20.03.2022 03:36

    В этом десятилетии лучшая практика cron — это использовать systemd timers.


    1. aik
      20.03.2022 06:42
      +5

      Если крон работает, зачем что-то другое искать?
      Да и строчку в кронтаб добавить проще, я думаю.


    1. unsignedchar
      20.03.2022 09:57
      -5

      Возможно, имеет смысл посмотреть на GUI для cron? Их мало, но есть.


  1. anonymous
    00.00.0000 00:00


  1. selivanov_pavel
    20.03.2022 05:23
    +9

    curl -fLsS -o /dev/null

    Понимаю, почему так делают, работая из командной строки. Но в скрипте не лучше ли использовать длинные опции:

    curl --fail --location --silent --show-error --output /dev/null

    Так есть шанс, что через пару месяцев получится прочитать этот однострочник сходу, не залезая в другой консоли в man.


  1. igrishaev
    20.03.2022 09:31
    +2

    Дополню: если процесс ничего не вывел, то письмо отправлено не будет. Поэтому я добавляю в конец `... && echo OK`, чтобы получить письмо при любом раскладе.


    1. isden
      20.03.2022 09:40
      +5

      Чтобы получить при любом раскладе — лучше что-то вроде ... ; echo OK.
      При использовании && выполнение echo произойдет только если предыдущая команда выполнилась успешно (с нулевым кодом возврата в большинстве систем).


      1. igrishaev
        20.03.2022 10:21

        Да, согласен. Имел в виду, что при любом *положительном* раскладе. При отрицательном всегда будет стек-трейс или сообщение об ошибке.


  1. simpleadmin
    20.03.2022 11:42
    +1

    Скрипт мог сломаться и вернуть 500 ошибок.

    Имелись ввиду 500-е коды ответа, а не количество, не переводите то чего не понимаете в принципе.


  1. Kirikekeks
    20.03.2022 12:59

    Совет перенести все задачи в анакрон, по мне очень хорош. С понятным именем, с комментом. Выглядит как логротэйт, и понимается отлично.


  1. amarao
    20.03.2022 15:30
    +2

    Лучшая практика cron - не использовать его.

    man systemd.timer


    1. edo1h
      20.03.2022 21:57

      пользуюсь, не нравится.
      в сравнении с кроном слишком много телодвижений получается.


  1. abagnale
    20.03.2022 16:33
    +1

    Я недавно озадачился мониторингом cron задач с нескольких серверов, чтобы можно было в одном месте видеть статусы по всем. Нашёл Healthchecks:

    По завершению очередной cron задачи отправляется HTTP запрос через cURL в API сервиса - так сервис узнаёт о её выполнении. Есть оповещения по почте, webhook (то есть и Telegram, хотя присутствует и отдельный вариант), Slack и прочие.

    Сервис доступен как на официальном сервере, так и для self-hosted установки (вот небольшая инструкция).


    1. amarao
      20.03.2022 18:09
      +1

      ... но на современном сервере он пропускает все таймеры.


      1. abagnale
        20.03.2022 18:19

        Что такое "современный сервер" и что значит "пропускает все таймеры"?

        Healthchecks это просто REST API сервис, который принимает HTTP запросы, а отправляются они с серверов, на которых выполняются cron задачи по расписанию. То есть вы говорите что у cron'а на серверах есть проблемы с точностью запуска задач по расписанию? Или что Healthchecks не соответствует расписанию cron и потому ожидает пингов от серверов в неправильное время?

        Так или иначе, я пока ничего похожего не заметил. У меня несколько серверов в разных временных зонах, и со всех пинги приходят вовремя.


        1. amarao
          20.03.2022 18:23
          +3

          Современный сервер, это сервер, на котором одна из указанных ОС:

          • Centos/RHEL 7, 8

          • Debian 9, 10, 11

          • Ubuntu 16.04, 18.04, 20.04, 22.04

          (и примерно соответствующие им другие ОС). Не современный сервер, к которому написанное не применимо: Centos 6, Debian 8, Ubuntu 14.04.

          На всех этих серверах в качестве pid 1 запущен процесс systemd.

          systemd поддерживает таймеры. man systemd.timer

          Это современный метод запуска периодических задач. А крон уже никто не использует давно, кроме легаси кода и почитателей статей образца 2010 года и раньше о том, что слаще крона джоб нет.

          TL;DR; на современном сервере большинство периодических задач запускается не кроном.


          1. abagnale
            20.03.2022 20:29

            А крон уже никто не использует давно

            Ну если вы всех остальных уже опросили, тогда выходит я один такой остался. У меня ни разу не было случая, чтобы cron задача не отработала в назначенное время. Останусь пока на нём.

            Кроме того, мой первый комментарий был больше не про cron, а про мониторинг выполнения запланированных задач, что скорее всего применимо и к этим таймерам от systemd.


            1. amarao
              20.03.2022 21:24
              +1

              Ну, хозяин барин, но большая часть системных событий всё равно на systemd уже переведена.


          1. aik
            21.03.2022 16:27

            TL;DR; на современном сервере большинство периодических задач запускается не кроном.

            Периодических или системных периодических?


            1. amarao
              21.03.2022 17:41

              Если вы зайдёте на сервер, там будет пачка задач. Более того, если вы добавите их как локальный системный администратор, то они всё равно будут системными, потому что есть ещё systemctl --user, и там тоже могут быть таймеры.


              1. aik
                21.03.2022 18:08

                Системный сервис — это системный сервис. А запуск программ по расписанию — это запуск программ по расписанию.

                Для меня системная задача — это та, которая обслуживание системы выполняет. К примеру, скачивать файлик вгетом — это не системная задача. Или папку домашнюю синхронизировать.

                Дальше, синтаксис крона — это дата и команда. Синтаксис системд — это целый файл сочинять надо. Да ещё потом разбираться, куда там дату вписывать.


                1. amarao
                  21.03.2022 18:12

                  OnCalendar=daily

                  Супер сложно, да.


                  1. aik
                    21.03.2022 18:18

                    И куда эту дату вписывать?
                    Правильно, в другой файл.

                    То есть вместо строки дата команда надо два файла писать. Да ещё с синтаксисом разбираться. И ради чего?


                    1. amarao
                      21.03.2022 18:21
                      +2

                      Например, ради того, чтобы задачи крона не складывались стопочкой из-за того, что предыдущая не успела отработать.

                      И чтобы можно было сделать list-timers и посмотреть когда следующая задача выполнится. И чтобы по задаче можно было сказать status и увидеть, выполнилась она или нет.

                      И чтобы не получить ситуацию, что cronjob стартанула до того, как запустились все её requirements на загрузке (или при шатдауне системы).

                      Это мы пока не обсуждали когда запускается задача crontab'а, если система sleep или shutdown на запланированное время.


                      1. aik
                        21.03.2022 18:28
                        +1

                        Ну и зачем мне всё это нужно, если мне просто файлик надо качать по расписанию? Я не говорю, что от системд надо отказываться — хотя и можно. Но если задача просто запускать команду по расписанию, то зачем всё усложнять?


                      1. amarao
                        21.03.2022 18:39

                        А что случится, если качающийся файлик по расписанию не скачается к моменту следующего расписания? Коррапт файла?


                      1. aik
                        21.03.2022 18:50
                        -1

                        Когда не скачается — тогда и буду разбираться.
                        Последние 20 лет всё работало нормально.


      1. Kirikekeks
        20.03.2022 20:51

        Таймеры можно, особенно если надо поставить "сторожок" действий на событие не устанавливая inotifywite incron из перечисленного в статье. Но тогда лучше это в motd сразу и написать, вместо "уважайте жизнь других". Расписания там (пока ?) мало кто ищет, это нехорошо, по отношению к коллегам до и "после меня". И не смешивать, или - или. Но рисовать три файла на задачу вместо одного, в чём побудительный мотив?


        1. amarao
          20.03.2022 21:25

          Кому нехорошо systemctl list-timers с временем, оставшимся до ближайшего срабатывания?

          Люди, вон, выше прям дашборды ваяют для крона для того же самого.


  1. 13werwolf13
    21.03.2022 07:30
    +4

    судя по коментариям кому нибудь давно пора написать статейку по сравнению cron и systemd timers, особо вменяемого на русском языке ничего не гуглится, ну или я гуглить разучился.


    1. Apokalepsis
      22.03.2022 17:29

      Вот вроде -https://habr.com/ru/company/ruvds/blog/512868/? , мне по крайне мере помогло разобраться, но так и не понял почему лучше.