Вопрос: Запуск задания cron вручную и сразу


(Я уже прочитал Как я могу проверить новый скрипт cron?.)

У меня есть конкретная проблема (задание cron не работает или работает нормально), но проблема в целом: я хотел бы отлаживать скрипты, которые выполняются. Я знаю, что я могу настроить строку * * * * * crontab, но это не вполне удовлетворительное решение. Я хотел бы иметь возможность запускать задание cron из командной строки, как если бы cron выполнял его (тот же пользователь, одни и те же переменные среды и т. Д.). Есть ли способ сделать это? Приходится ждать 60 секунд, чтобы протестировать изменения скриптов нецелесообразно.


93
2017-11-18 13:55


Источник


(извините, не могу добавить комментарий) 0 30 16 20 *? * даже если вы выполняете эту работу, вся идея состоит в том, чтобы предоставить вывод сценария, чтобы увидеть, что происходит, если работа не записывается в журнал, это бесполезно


Ответы:


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


Шаг 1: Я временно помещал эту строку в crontab пользователя:

* * * * *   /usr/bin/env > /home/username/tmp/cron-env

затем вытащил его после того, как файл был записан.

Шаг 2: Сделал себе небольшой скрипт run-as-cron bash, содержащий:

#!/bin/bash
/usr/bin/env -i $(cat /home/username/tmp/cron-env) "$@"

Итак, как пользователь, о котором идет речь, я смог

run-as-cron /the/problematic/script --with arguments --and parameters

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

Надеюсь, это поможет другим.


73
2017-11-18 14:40



Это не работает для меня, и я задаюсь вопросом, действительно ли это для любого, кто его поддержал. 1) Почему вы используете bash? Здесь не требуется, и это может быть не /usr/bin, 2) cat …/cron-env выводит несколько строк, что не работает. Просто попробуйте выполнить /usr/bin/env -i $(cat cron-env) echo $PATH в терминале он выводит среду буквально, а не использует ее. 3) Текущая среда протекает в эмулируемой среде cron. Пытаться: export foo=leaked; run-as-cron echo $foo, - Marco
@Marco Работает в bash, и это то, что я использую, поскольку это более определенная среда, чем sh. Я использую все: от pdksh, ksh (несколько версий), bash и dash, поэтому я очень хорошо разбираюсь в различиях между реализациями «чистого» sh, даже если вы строго придерживаетесь общего подмножества языков. :-) - Max Murphy
@Marco 2. cat выводит несколько строк, которые работают, потому что замена оболочки сворачивает их в одну строку, которую вы можете проверить с помощью echo $(cat cron-env ) | wc; ваш пример команды, /usr/bin/env -i $(cat cron-env) echo $PATH, заменители $PATH из вызывающей оболочки; вместо этого он должен ссылаться на подоболочку, чтобы подставить в подслушивание, например. /usr/bin/env -i $(cat cron-env) /bin/sh -c 'echo $PATH', 3. Вы совершили ту же ошибку, снова заменив вызывающую оболочку, а не в подкапитале - John Freeman


Я представляю решение, основанное на ответе Писто, но без недостатков.

  • Добавьте следующую строку в crontab, например. с помощью crontab -e

    * * * * *  /usr/bin/env > /home/username/cron-env
    
  • Создайте сценарий оболочки, который выполняет команду в той же среде, где выполняются задания cron:

    #!/bin/sh
    
    . "$1"
    exec /usr/bin/env -i "$SHELL" -c ". $1; $2"
    

Использование:

run-as-cron <cron-environment> <command>

например

run-as-cron /home/username/cron-env 'echo $PATH'

Обратите внимание, что второй аргумент должен быть указан, если для этого требуется аргумент. Первая строка скрипта загружает оболочку POSIX в качестве интерпретатора. Вторая строка содержит файл среды cron. Это необходимо для загрузки правильной оболочки, которая хранится в переменной окружения SHELL, Затем он загружает пустую среду (чтобы предотвратить утечку переменных среды в новую оболочку), запускает ту же оболочку, которая используется для cronjobs и загружает переменные среды cron. Наконец, команда выполнена.


32
2017-09-24 18:46



это помогло мне воспроизвести мою ошибку загрузки сфинкса, связанную с рубином. - cweiske
Я использовал параметр @reboot cron для записи файла cron-env. Затем вы можете оставить его в crontab, и он будет перезаписан только при запуске системы. Это делает его немного проще, поскольку вам не нужно добавлять / удалять строки. - Michael Barton


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

crontab -l | grep -v '^#' | cut -f 6- -d ' ' | while read CMD; do eval $CMD; done

Что оно делает :

  • списки crontab jobs
  • удалить строки комментариев
  • удалить конфигурацию crontab
  • затем запускайте их один за другим

14
2017-08-19 19:45



Это не обязательно делает это в той же среде, что и cron, и я думал, что он хочет проверить только один из них. - Falcon Momot
Правильно, я ошибся ... Он работает только на рабочих местах, но не так, как сделал cron! - Django Janny
все еще удивительное решение +1 - Eric Uldall


По умолчанию с большинством дефолтных демонах cron, которые я видел, просто нет способа сообщить cron, чтобы он работал прямо здесь прямо сейчас. Если вы используете anacron, возможно, я думаю, что для запуска отдельного экземпляра на переднем плане.

Если ваши сценарии не работают должным образом, вы не принимаете во внимание, что

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

Из crontab (5):

Установлены несколько переменных среды   автоматически с помощью cron (8)   демон. SHELL установлен в / bin / sh и   LOGNAME и HOME установлены с   / etc / passwd линии crontab's   владелец. Для параметра PATH установлено значение «/ usr / bin: / bin».   HOME, SHELL и PATH могут быть   переопределение настроек в   кронтаб; LOGNAME является пользователем, что   работа выполняется, и может не быть   изменилось.

В общем, PATH - самая большая проблема, поэтому вам нужно:

  • Явно установите PATH внутри скрипта во время тестирования в / usr / bin: / bin. Вы можете сделать это в bash с export PATH = "/ usr / bin: / bin"
  • Явно задайте правильный PATH, который вы хотите, в верхней части crontab. например PATH = "/ USR / бен: / бен: / USR / местные / бен: / USR / SBIN: / SBIN"

Если вам нужно запустить сценарий как другого пользователя без оболочки (например, www-data), используйте sudo:

sudo -u www-data /path/to/crontab-script.sh

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


5
2017-11-18 14:27



Благодарим вас за тщательный ответ. Я знаю о двух проблемах работы как с конкретным пользователем, так и с конкретной средой. Таким образом, я сформулировал свой собственный ответ, который я теперь опубликую ... - Pistos
Символы Escape являются допустимыми причинами отсутствия работы - Joe Phillips


Ну, пользователь такой же, как тот, который вы вложили в запись crontab (или чей crontab вы вставляете его поочередно), так что это не проблема. crontab(5) должен предоставить вам список переменных окружения, есть только несколько.


1
2017-11-18 14:04



Другими словами, вы говорите, что нет способа сделать это? Только «достаточно близкие» обходные пути? - Pistos
Нет, я говорю, что вы можете это сделать, используя информацию, которую я предоставил в своем ответе. - womble♦


В большинстве crontab, например, например, vixie-cron вы можете поместить переменные в самом crontab, как это, а затем использовать / usr / bin / env, чтобы проверить, работает ли это. Таким образом, вы можете заставить свой скрипт работать в crontab, как только вы узнаете, что случилось с сценарием run-as-cron.

SHELL=/bin/bash
LANG=en
FASEL=BLA

* * * * *   /usr/bin/env > /home/username/cron-env

1
2017-10-27 06:52





Сценарий Марко почему-то не сработал для меня. У меня не было времени на отладку, поэтому я написал скрипт Python, который делает то же самое. Это длиннее, но: во-первых, это работает для меня, а во-вторых, мне легче понять. Измените «/ tmp / cron-env» на место, где вы сохранили среду. Вот:

#!/usr/bin/env python
from __future__ import division, print_function

import sys
import os

def main():
    if len(sys.argv) != 2 or sys.argv[1] in ('-h', '--help'):
        print("Usage: {} CMD\n"
              "Run a command as cron would. Note that CMD must be quoted to be only one argument."
              .format(sys.argv[0]))
        sys.exit(1)
    _me, cmd = sys.argv
    env = dict(line.strip().split('=', 1) for line in open('/tmp/cron-env'))
    sh = env['SHELL']
    os.execvpe(sh, [sh, '-c', cmd], env)

if __name__ == '__main__':
    main()

1
2017-12-24 08:48





Решение Marco не сработало для меня, но скрипт python от Noam работал. Вот небольшая модификация сценария Марко, которая заставила его работать для меня:

#!/bin/sh
. "$1"
exec /usr/bin/env -i "$SHELL" -c "set -a;. $1; $2"

Добавленный set -a экспортные переменные, определенные в скрипте $ 1, и сделали его доступным для команды $ 2

постскриптум Питон Noam работал, потому что он «экспортировал» среду в дочерний процесс.


1
2018-05-11 05:05





Я никогда не нашел способ запуска заданий cron вручную, но это write-up предлагает установить ту же среду, что и cronjob, и запустить скрипт вручную.


0
2017-11-18 14:07



Разве вы не хотите делать то, что OP хочет знать, как это сделать? - womble♦
Вот почему я включил ссылку на запись, которая описывает, как это сделать. Я не счел нужным копировать все здесь. - oneodd1