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

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

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

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

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

21 ответ

Решение

Это всегда хорошо для меня.

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

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

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

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

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

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

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

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

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

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

Добавить что-то в 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 -

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

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

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

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

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

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

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

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

cat <file> |crontab -

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

EDITOR экспорта ="тройник"

echo "0 * * * * / bin / echo 'Hello World'" | crontab -e

Предполагая, что в вашем 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 -

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

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

(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 -

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
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');

В добавление к ответу JohnZ, вот синтаксис для назначения в качестве root, если вы sudoer:

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

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

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

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

Лучше всего использовать сборник пьес Ansible со следующей задачей:

      ---
- name: Deploy cron
  hosts: all
  gather_facts: false
  tasks:
    - name: Update Cron job
      ansible.builtin.cron:
        name: Run Drupal Cron Job
        user: www-data
        minute: "0"
        job: "/var/www/html/drupal/vendor/bin/drush core:cron"

В приведенном выше решении используетсяdrush core:cron, поскольку недавние вызовы cron Drupal требуют ключей (которые нужно было извлечь, а затем жестко запрограммировать).

См.: Настройка заданий cron с помощью команды cron .

Затем используйтеansible-playbook -i hosts deploy.ymlзапустить его, гдеhostsфайл:

      echo "[all]\n\192.168.0.123   ansible_connection=ssh    ansible_user=root" > hosts

где192.168.0.123ваш хост для развертывания.

Вы можете использовать его как часть сценариев развертывания или поместить в свойJenkinsfileкак часть вашего конвейера развертывания.

Чтобы иметь гибкость при изменении команды в будущем, вы можете сделать это (лучше всего работает со сценарием обновления)

MARK=SOME_UNIQUE_MARK_TEXT
LINE="This is the command # $MARK"
# NOTE: I'm using -e because I might want to avoid weird bash expansions for '*' or '$' and place:
# \x2A instead of *
# \x24 instead of $
( crontab -l | grep -v $MARK ; echo -e "0 * * * *" $LINE ) | crontab -

Таким образом я могу обновить старую команду crontab, которая больше не служит текущей цели.

В основном я получаю текущий crontab, я удаляю строку, содержащую MARK (grep -v) и замените его новым, добавив в конец файла crontab через echo -e. В этом конкретном случае я хочу, чтобы он выполнялся каждый час в минуту 0 0 * * * *как это видно отсюда.

Ниже то, что я использую в своем скрипте

1.

(2>/dev/null crontab -l ; echo "0 3 * * * /usr/local/bin/certbot-auto renew") | crontab -
cat <(crontab -l 2>/dev/null) <(echo "0 3 * * * /usr/local/bin/certbot-auto renew") | crontab -

# записать текущий crontab

crontab -l > mycron 2>/dev/null

# вывод нового cron в файл cron

echo "0 3 * * * /usr/local/bin/certbot-auto renew" >> mycron

# установить новый файл cron

crontab mycron

rm mycron

Я добавляю решения, подобные решениям @JohnZ, которые не добавляют дубликатов, сохраняя при этом существующий порядок crontab. У нас довольно много вакансий, которые сильно комментируются, и нам нужно сохранить эту структуру.

      $ { \
    crontab -l; \
    echo "*/1  * * * *   echo job one"  &>/dev/null; \
    echo "*/30 * * * *   echo job two"  &>/dev/null; \
  } | awk '(/^#/ || !a[$0]++)' | crontab -

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

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

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

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'

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

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

Другие вопросы по тегам