Как я могу программно создать новое задание cron?


131

Я хочу иметь возможность программно добавлять новое задание cron, как лучше всего это сделать?

Из моих исследований кажется, что я мог бы сбросить текущий crontab, а затем добавить новый, отправив его обратно в crontab:

(crontab -l ; echo "0 * * * * wget -O - -q http://www.example.com/cron.php") | crontab -

Есть ли способ лучше?


2
Ваше решение кажется хорошим.
Craig S

В Solaris просто удалите тире для последнего crontab. Вы можете добавить grep, чтобы не добавлять уже существующую строку.
lacroix1547


фигурные скобки вместо скобок сделают это без порождения процесса. Обязательно оставьте пробелы вокруг фигурных скобок, {...; }.
Джей Уинстон

Ответы:


-25

У меня это всегда хорошо получалось.

Вам следует подумать о более сложном сценарии, который может делать три вещи.

  1. Добавить строку crontab; уверяя, что его не было. Добавлять, когда он уже существует, - плохо.

  2. Удалите строку crontab. Возможно, только предупреждение, если его не было.

  3. Комбинация двух вышеуказанных функций для замены строки crontab.


78
Он спрашивает, как, а вы ему что?
Cerin

1
Что делать, если у пользователя еще нет crontab?
Максим Егорушкин

134

Лучший способ, если вы работаете с правами root, - это поместить файл в /etc/cron.d

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

Имя файла: /etc/cron.d/per_minute

Содержание: * * * * * root /bin/sh /home/root/script.sh


5
Просто убедитесь, что используемая версия cron поддерживает /etc/cron.d/. Большинство современных дистрибутивов Linux это делают.
sleske 06

8
Это самое простое и элегантное решение. Конечно, лучше, чем разбирать и редактировать существующий crontab с другими не связанными записями.
Cerin

13
Одно из возможных предупреждений - частота, с которой cron получает новые дополнения к этой папке (один раз в час). Если вы ожидаете, что ваша работа сразу же начнет работать, будьте осторожны.
JonathanK

6
@JonathanK, вы случайно не знаете, можно ли попросить cron выполнить повторное сканирование /etc/cron.d/*? Трудно понять, работает ли что-то, если нужно подождать час, чтобы проверить!
Halfer

4
как установить perms для этого файла? chmod + x /etc/cron.d/per_minute?
Giò

101

В решении OP есть ошибка, это может позволить добавлять записи дважды, используйте ниже, чтобы исправить.

(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -

5
На самом деле это лучшее, если не описанное решение. Это гарантирует, что команда не будет дважды добавлена ​​в crontab.
Bufke

2
Это вряд ли хорошее решение проблемы дублирования записей. Что, если тем временем в crontab была добавлена ​​еще одна строка?
hmn

6
Чтобы обеспечить уникальность, непосредственно sortперед uniq, например:(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
mway

6
Нет необходимости в uniq. Используйте -uопцию на sort.
papiro

6
как избежать отсутствия crontab для пользователя при первом редактировании crontab.
wyx

23

Добавить что-нибудь в cron

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | sort | uniq | crontab -

Чтобы удалить это из cron

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | grep -v hupChannel.sh |  sort | uniq | crontab -

надеюсь поможет кому-то


Это именно то, что я искал, я бы просто добавил это: | grep -v '^ #' | чтобы отфильтровать комментарии
Tjunkie

2
На самом деле вам не нужно, 2>&1 | grep -v "no crontab"потому что, когда нет crontab, строка вывода crontab: no crontab for...отправляется на stderr. Нет причин записывать этот вывод, отправлять его на стандартный вывод, а затем отфильтровывать с помощью grep. Если ваша цель - избежать crontab: no crontab for...вывода результатов, используйте 2> /dev/null | sort.....
Мэтти 02

6

Если вы планируете сделать это для сценария однократного запуска, чтобы просто что-то получить, взгляните на 'at'


6

Просто измените редактор на команду tee:

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e

4
Осторожно - это стирает все существующие записи.
starfry

5

Предполагая, что в вашем crontab уже есть запись, следующая команда должна работать относительно хорошо. Обратите внимание, что $CMDпеременная предназначена только для удобства чтения. Сортировка перед фильтрацией дубликатов важна, потому что uniqработает только с соседними строками.

CMD='wget -O - -q http://www.example.com/cron.php"'
(crontab -l ; echo "0 * * * * $CMD") | sort | uniq | crontab -

Если у вас в настоящее время пустой crontab, вы получите следующую ошибку для stderr:

no crontab for user

Если вы хотите избежать этого, вы можете добавить немного сложности и сделать что-то вроде этого:

(crontab -l ; echo "0 * * * * $CMD") 2>&1 | sed "s/no crontab for $(whoami)//"  | sort | uniq | crontab -

5

Большинство решений здесь предназначены для добавления строк в crontab. Если вам нужен больший контроль, вы захотите иметь возможность контролировать все содержимое crontab.

Вы можете сделать это довольно элегантно с помощью трубопроводов.

Чтобы полностью переписать crontab, выполните

echo "2 2 2 2 2 /bin/echo foobar" |crontab -

Это должно быть легко совместить с другими ответами, описанными здесь, например

crontab -l | <something> | tee |crontab -

Или, если у вас есть содержимое в файле, это еще проще

cat <file> |crontab -

3

Вот еще один однострочный способ, позволяющий избежать дублирования

(crontab -l 2>/dev/null | fgrep -v "*/1 *  *  *  * your_command"; echo "*/1 *  *  *  * your_command") | crontab -

И вот способ ответить JohnZ и избежать no crontab for userсообщения, или если вам нужно работать в set -euсреде типов и ничего не может вернуть ошибку (в этом случае 2>/dev/nullчасть является необязательной):

( (crontab -l 2>/dev/null || echo "")  ; echo "0 * * * * your_command") | sort -u - | crontab -

Или, если вы хотите разделить вещи, чтобы они были более читабельны:

new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
(echo "$preceding_cron_jobs" ; echo "$new_job") | sort - | uniq - | crontab -

Или, при желании, удалите все ссылки на your_command (например: если расписание изменилось, вы хотите, чтобы оно выполнялось только один раз). В этом случае нам больше не нужны uniq(добавлен бонус, сохраняется порядок вставки):

new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
preceding_cron_jobs=$(echo "$preceding_cron_jobs" | grep -v your_command )
(echo "$preceding_cron_jobs" ; echo "$new_job") | crontab -

2

man crontab также полезен:

CRONTAB (1)

НАЗВАНИЕ

   crontab - manipulate per-user crontabs (Dillon's Cron)

СИНТАКСИС

   crontab file [-u user] - replace crontab from file

   crontab - [-u user] - replace crontab from stdin

   crontab -l [user] - list crontab for user

3
Часть, в которой говорится «заменить crontab из stdin», на самом деле является половиной ответа :-)
Grodriguez

2

Добавляя к ответу JohnZ, вот синтаксис для планирования с правами root, если вы sudoer:

(sudo crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | sudo crontab -

1
function cronjob_exists($command){

    $cronjob_exists=false;

    exec('crontab -l', $crontab);


    if(isset($crontab)&&is_array($crontab)){

        $crontab = array_flip($crontab);

        if(isset($crontab[$command])){

            $cronjob_exists=true;

        }

    }
    return $cronjob_exists;
}

function append_cronjob($command){

    if(is_string($command)&&!empty($command)&&cronjob_exists($command)===FALSE){

        //add job to crontab
        exec('echo -e "`crontab -l`\n'.$command.'" | crontab -', $output);


    }

    return $output;
}

    append_cronjob('* * * * * curl -s http://localhost/cron/test.php');

1

Это позволит убедиться, что ваша команда еще не существует, перед ее добавлением.

crontab -l 2>/dev/null | grep -q '/path/to/script' || echo "5 * * * * /path/to/script" | crontab -

Приветствия.


0

При вводе стандартного вывода в crontabmacOS мне не удалось установить новый crontab, поэтому я нашел это решение, используя teeредактор во вспомогательной оболочке:

(EDITOR=tee && (crontab -l ; echo "@daily ~/my-script.sh" ) | uniq - | crontab -e)

0

Если вы хотите, чтобы задача запускалась от имени пользователя:

crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | crontab -

Если вы хотите, чтобы задача выполнялась с правами:

sudo crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | sudo crontab -

и проверьте задачу (с sudo или без):

crontab -l | sed '/^$/d; /#/d'


-2

Вы также можете напрямую отредактировать текстовый файл таблицы cron, но ваше решение кажется вполне приемлемым.


1
Я бы с подозрением отнесся к этому из-за опасений, что одновременное редактирование может привести к повреждению файла. Использование команды crontab из командной строки должно избежать этой проблемы.
Craig S

Крейг, без дополнительных исследований я не был бы уверен, что версия командной строки атомарна и безопасна по условиям гонки. В любом случае, наверное, «вполне безопасно».
tuomassalo

«Редактирование файла напрямую» невозможно без корневого доступа (при условии, что вы можете выяснить, где находится файл crontab пользователя и как убедиться, что демон cron правильно принимает ваши изменения), а «редактирование» программно, похоже, вот в чем вопрос в первую очередь хочет совета.
Tripleee
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.