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

131

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

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

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

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

davidmytton
источник
2
Ваше решение кажется хорошим.
Craig S
В Solaris просто удалите тире для последнего crontab. Вы можете добавить grep, чтобы не добавлять уже существующую строку.
lacroix1547
Возможный дубликат Как создать задание cron с помощью Bash
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
фигурные скобки вместо скобок сделают это без порождения процесса. Обязательно оставьте пробелы вокруг фигурных скобок, {...; }.
Джей Уинстон

Ответы:

-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

MarkR
источник
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 -
JohnZ
источник
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 -

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

user3865482
источник
Это именно то, что я искал, я бы просто добавил это: | 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 -
Eldamir
источник
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 -
rogerdpack
источник
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
vitaly.v.ch
источник
3
Часть, в которой говорится «заменить crontab из stdin», на самом деле является половиной ответа :-)
Grodriguez
2

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

(sudo crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | sudo crontab -
BuvinJ
источник
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');
RafaSashi
источник
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'
ajcg
источник
-1

также вы можете добавлять свои задачи в /etc/cron.*/

vitaly.v.ch
источник
-2

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

Алекс Форт
источник
1
Я бы с подозрением отнесся к этому из-за опасений, что одновременное редактирование может привести к повреждению файла. Использование команды crontab из командной строки должно избежать этой проблемы.
Craig S
Крейг, без дополнительных исследований я не был бы уверен, что версия командной строки атомарна и безопасна по условиям гонки. В любом случае, наверное, «вполне безопасно».
tuomassalo
«Редактирование файла напрямую» невозможно без корневого доступа (при условии, что вы можете выяснить, где находится файл crontab пользователя и как убедиться, что демон cron правильно принимает ваши изменения), а «редактирование» программно, похоже, вот в чем вопрос в первую очередь хочет совета.
Tripleee