Проверьте, запускается ли скрипт cron, а не вызывается вручную
23
Есть ли переменная, которую устанавливает cron при запуске программы? Если скрипт запускается cron, я бы хотел пропустить некоторые части; в противном случае вызовите эти части.
@terdon: вероятно потому, что psон довольно плохо документирован (особенно версия Linux, которая поддерживает несколько различных синтаксических стилей), а страница руководства даже более плотная и загадочная, чем большинство инструментов. Я подозреваю, что большинство людей даже не осознают, насколько полезным и универсальным psможет быть инструмент .
Cas
Ответы:
31
Я не знаю, cronчто по умолчанию делает что-то для его среды, что может быть здесь полезно, но есть несколько вещей, которые вы могли бы сделать, чтобы получить желаемый эффект.
1) Сделать жесткую или программную ссылку на файл скрипта, чтобы, например, myscriptи myscript_via_cronуказать на тот же файл. Затем вы можете проверить значение $0внутри скрипта, если хотите условно запустить или пропустить определенные части кода. Поместите подходящее имя в ваш crontab, и все готово.
2) Добавьте параметр в сценарий и установите этот параметр в вызове crontab. Например, добавьте параметр -c, который указывает сценарию запускать или пропустить соответствующие части кода, и добавьте -cимя команды в ваш crontab.
И, конечно же, cron может устанавливать произвольные переменные окружения, поэтому вы можете просто вставить строку, как RUN_BY_CRON="TRUE"в вашем crontab, и проверить ее значение в вашем скрипте.
Ответ от cas работает очень хорошо и может быть использован для чего угодно еще
Deian
19
Скрипты, запускаемые из cron, не запускаются в интерактивных оболочках. Ни один из сценариев запуска. Различие состоит в том, что к интерактивным оболочкам подключены STDIN и STDOUT к tty.
Способ 1: проверьте, $-включает ли iфлаг. iустанавливается для интерактивных оболочек.
Способ 3: проверить свой tty. это не так надежно, но с простыми заданиями cron вы должны быть в порядке, так как cron по умолчанию не выделяет tty для скрипта.
Обратите внимание, что команда $ PS1 не работает при проверке запуска сценария systemd или нет. $ - один делает
mveroone
1
Ваша ссылка на Виннипегский университет не работает.
WinEunuuchs2Unix
1
@TimKennedy Не за что .... из Эдмонтона :)
WinEunuuchs2Unix
'case "$ -" in' не работает в скриптах bash.
Хобади
@ Hobadee - у каждого bash, к которому у меня есть доступ, есть $, как dashи у ksh. даже в оболочках Solaris с ограниченным доступом. Какую платформу вы пытаетесь использовать там, где она не работает? Что case "$-" in *i*) echo true ;; *) echo false ;; esacпоказывает тебе?
Тим Кеннеди
7
Сначала получите PID cron, затем PID родительского текущего процесса (PPID) и сравните их:
CRONPID=$(ps ho %p -C cron)
PPID=$(ps ho %P -p $$)if[ $CRONPID -eq $PPID ];then echo Cron is our parent.;fi
Если ваш скрипт запускается другим процессом, который мог быть запущен cron, вы можете вернуться к родительским PID, пока не доберетесь до $ CRONPID или 1 (PID init).
может быть что-то вроде этого (Untested-But-It-Might-Work <TM>):
PPID=$$ # start from current PID
CRON_IS_PARENT=0
CRONPID=$(ps ho %p -C cron)while[ $CRON_IS_PARENT -ne 1]&&[ $PPID -ne 1];do
PPID=$(ps ho %P -p $PPID)[ $CRONPID -eq $PPID ]&& CRON_IS_PARENT=1done
От Deian: это версия, протестированная на RedHat Linux
# start from current PID
MYPID=$$
CRON_IS_PARENT=0# this might return a list of multiple PIDs
CRONPIDS=$(ps ho %p -C crond)
CPID=$MYPID
while[ $CRON_IS_PARENT -ne 1]&&[ $CPID -ne 1];do
CPID_STR=$(ps ho %P -p $CPID)# the ParentPID came up as a string with leading spaces# this will convert it to int
CPID=$(($CPID_STR))# now loop the CRON PIDs and compare them with the CPIDfor CRONPID in $CRONPIDS ;do[ $CRONPID -eq $CPID ]&& CRON_IS_PARENT=1# we could leave earlier but it's okay like that toodonedone# now do whatever you want with the informationif["$CRON_IS_PARENT"=="1"];then
CRON_CALL="Y"else
CRON_CALL="N"fi
echo "CRON Call: ${CRON_CALL}"
В Solaris cron запускает оболочку, а оболочка запускает скрипт, который сам запускает другую оболочку. Таким образом, родительский pid в скрипте не является pid cron.
ceving
4
Если ваш файл скрипта вызывается cronи содержит в первой строке оболочку, как #!/bin/bashвам нужно найти имя родительского-родителя для вашей цели.
1) cronвызывается в данный момент в вашем crontab, выполняя оболочку 2) оболочка выполняет ваш скрипт 3) ваш скрипт выполняется
Родительский PID доступен в bash как переменная $PPID. Команда psдля получения родительского PID родительского PID:
PPPID=`ps h -o ppid= $PPID`
но нам нужно имя команды, а не pid, поэтому мы называем
P_COMMAND=`ps h -o %c $PPPID`
теперь нам просто нужно проверить результат для "cron"
Это работает только для Linux PS. Для MacOS (а также для Linux, может быть, * BSD тоже), вы можете использовать следующую P_COMMAND:P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
mdd
1
Работает на FreeBSD или на Linux:
if["Z$(ps o comm="" -p $(ps o ppid="" -p $$))"=="Zcron"-o \
"Z$(ps o comm="" -p $(ps o ppid="" -p $(ps o ppid="" -p $$)))"=="Zcron"]then
echo "Called from cron"else
echo "Not called from cron"fi
Вы можете пойти так далеко вверх по дереву процессов, как пожелаете.
Нет никакого авторитетного ответа, но переменные prompt ( $PS1) и Terminal ( $TERM) здесь вполне приличные. Некоторые системы установлены, в TERM=dumbто время как большинство оставляют это пустым, поэтому мы просто проверим:
if["${TERM:-dumb}$PS1"!="dumb"];then
echo "This is not a cron job"fi
Приведенный выше код заменяет слово «тупой», если для него нет значения $TERM. Таким образом, условный вызов срабатывает, когда нет $TERMили $TERMзадано значение «немой» или если $PS1переменная не пуста.
Я протестировал это на Debian 9 ( TERM=), CentOS 6.4 и 7.4 ( TERM=dumb) и FreeBSD 7.3 ( TERM=).
ps
?ps
он довольно плохо документирован (особенно версия Linux, которая поддерживает несколько различных синтаксических стилей), а страница руководства даже более плотная и загадочная, чем большинство инструментов. Я подозреваю, что большинство людей даже не осознают, насколько полезным и универсальнымps
может быть инструмент .Ответы:
Я не знаю,
cron
что по умолчанию делает что-то для его среды, что может быть здесь полезно, но есть несколько вещей, которые вы могли бы сделать, чтобы получить желаемый эффект.1) Сделать жесткую или программную ссылку на файл скрипта, чтобы, например,
myscript
иmyscript_via_cron
указать на тот же файл. Затем вы можете проверить значение$0
внутри скрипта, если хотите условно запустить или пропустить определенные части кода. Поместите подходящее имя в ваш crontab, и все готово.2) Добавьте параметр в сценарий и установите этот параметр в вызове crontab. Например, добавьте параметр
-c
, который указывает сценарию запускать или пропустить соответствующие части кода, и добавьте-c
имя команды в ваш crontab.И, конечно же, cron может устанавливать произвольные переменные окружения, поэтому вы можете просто вставить строку, как
RUN_BY_CRON="TRUE"
в вашем crontab, и проверить ее значение в вашем скрипте.источник
Скрипты, запускаемые из cron, не запускаются в интерактивных оболочках. Ни один из сценариев запуска. Различие состоит в том, что к интерактивным оболочкам подключены STDIN и STDOUT к tty.
Способ 1: проверьте,
$-
включает лиi
флаг.i
устанавливается для интерактивных оболочек.Способ 2: проверка
$PS1
пуста.ссылка: http://techdoc.kvindesland.no/linux/gnubooks/bash/bashref_54.html
Способ 3: проверить свой tty. это не так надежно, но с простыми заданиями cron вы должны быть в порядке, так как cron по умолчанию не выделяет tty для скрипта.
Имейте в виду, что вы можете принудительно использовать интерактивную оболочку
-i
, но вы, вероятно, будете знать, если бы вы делали это ...источник
bash
, к которому у меня есть доступ, есть $, какdash
и уksh
. даже в оболочках Solaris с ограниченным доступом. Какую платформу вы пытаетесь использовать там, где она не работает? Чтоcase "$-" in *i*) echo true ;; *) echo false ;; esac
показывает тебе?Сначала получите PID cron, затем PID родительского текущего процесса (PPID) и сравните их:
Если ваш скрипт запускается другим процессом, который мог быть запущен cron, вы можете вернуться к родительским PID, пока не доберетесь до $ CRONPID или 1 (PID init).
может быть что-то вроде этого (Untested-But-It-Might-Work <TM>):
От Deian: это версия, протестированная на RedHat Linux
источник
Если ваш файл скрипта вызывается
cron
и содержит в первой строке оболочку, как#!/bin/bash
вам нужно найти имя родительского-родителя для вашей цели.1)
cron
вызывается в данный момент в вашемcrontab
, выполняя оболочку 2) оболочка выполняет ваш скрипт 3) ваш скрипт выполняетсяРодительский PID доступен в bash как переменная
$PPID
. Командаps
для получения родительского PID родительского PID:но нам нужно имя команды, а не pid, поэтому мы называем
теперь нам просто нужно проверить результат для "cron"
Теперь вы можете проверить в любом месте вашего скрипта
Удачи!
источник
P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
Работает на FreeBSD или на Linux:
Вы можете пойти так далеко вверх по дереву процессов, как пожелаете.
источник
Типичное решение вопроса «является ли мой вывод терминалом или я запускаю из скрипта»:
источник
Простое
echo $TERM | mail me@domain.com
в cron показало мне, что как в Linux, так и в AIX cron, похоже, установлен$TERM
в «тупой».Теперь теоретически все еще могут быть реальные тупые терминалы, но я подозреваю, что в большинстве случаев этого должно быть достаточно ...
источник
Нет никакого авторитетного ответа, но переменные prompt (
$PS1
) и Terminal ($TERM
) здесь вполне приличные. Некоторые системы установлены, вTERM=dumb
то время как большинство оставляют это пустым, поэтому мы просто проверим:Приведенный выше код заменяет слово «тупой», если для него нет значения
$TERM
. Таким образом, условный вызов срабатывает, когда нет$TERM
или$TERM
задано значение «немой» или если$PS1
переменная не пуста.Я протестировал это на Debian 9 (
TERM=
), CentOS 6.4 и 7.4 (TERM=dumb
) и FreeBSD 7.3 (TERM=
).источник