Compruebe si cron inicia el script, en lugar de invocarlo manualmente
23
¿Hay alguna variable que cron establece cuando ejecuta un programa? Si cron ejecuta el script, me gustaría omitir algunas partes; de lo contrario invoque esas partes.
¿Cómo puedo saber si el script Bash es iniciado por cron?
@terdon: probablemente porque psestá bastante mal documentado (especialmente la versión de Linux que admite varios estilos de sintaxis diferentes) y la página de manual es aún más densa y críptica que la mayoría de las herramientas. Sospecho que la mayoría de las personas ni siquiera se dan cuenta de cuán útil y versátil pspuede ser una herramienta .
cas
Respuestas:
31
No soy consciente de que cronhace algo en su entorno por defecto que puede ser útil aquí, pero hay un par de cosas que podría hacer para obtener el efecto deseado.
1) Haga un enlace fijo o suave al archivo de script, de modo que, por ejemplo, myscripty myscript_via_cronapunte al mismo archivo. A continuación, puede probar el valor $0dentro del script cuando desea ejecutar u omitir condicionalmente ciertas partes del código. Pon el nombre apropiado en tu crontab y listo.
2) Agregue una opción al script y establezca esa opción en la invocación crontab. Por ejemplo, agregue una opción -c, que le dice al script que ejecute u omita las partes apropiadas del código, y agregue -cal nombre del comando en su crontab.
Y, por supuesto, cron puede establecer variables de entorno arbitrarias, por lo que podría poner una línea como RUN_BY_CRON="TRUE"en su crontab y verificar su valor en su script.
la respuesta de cas funciona muy bien y también se puede utilizar para cualquier otra cosa
Deian
19
Los scripts ejecutados desde cron no se ejecutan en shells interactivos. Tampoco los scripts de inicio. La diferencia es que los shells interactivos tienen STDIN y STDOUT unidos a un tty.
Método 1: verifique si $-incluye la ibandera. iestá configurado para shells interactivos.
Método 3: prueba tu tty. no es tan confiable, pero para trabajos cron simples debería estar bien, ya que cron no asigna por defecto un tty a un script.
Tenga en cuenta que el comando $ PS1 no funciona cuando se verifica si el script es iniciado por systemd o no. the $ - one does
mveroone
1
Su enlace de la Universidad de Winnipeg está roto.
WinEunuuchs2Unix
1
@TimKennedy De nada ... de Edmonton :)
WinEunuuchs2Unix
'case "$ -" in' no parece funcionar en scripts de bash.
Hobadee
@Hobadee: cada uno al que bashtengo acceso tiene $ -, al igual que dashy ksh. incluso las conchas restringidas en Solaris lo tienen. ¿Qué plataforma estás tratando de usar cuando no funciona? ¿Qué case "$-" in *i*) echo true ;; *) echo false ;; esacte muestra?
Tim Kennedy
7
Primero, obtenga el PID de cron, luego obtenga el PID principal (PPID) del proceso actual y compárelos:
CRONPID=$(ps ho %p -C cron)
PPID=$(ps ho %P -p $$)if[ $CRONPID -eq $PPID ];then echo Cron is our parent.;fi
Si su secuencia de comandos es iniciada por otro proceso que podría haber sido iniciado por cron, entonces puede volver a subir los PID principales hasta llegar a $ CRONPID o 1 (PID de init).
algo como esto, tal vez (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
De Deian: esta es una versión probada en 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}"
En Solaris, cron inicia un shell y el shell ejecuta el script, que a su vez inicia otro shell. Entonces el padre pid en el script no es el pid de cron.
ceving
4
Si su archivo de script es invocado por crony contiene un shell en la primera línea como #!/bin/bashsi necesitara encontrar el nombre padre-padre para su propósito.
1) cronse invoca en el momento dado en su crontab, ejecutando un shell 2) el shell ejecuta su script 3) su script se está ejecutando
El PID principal está disponible en bash como variable $PPID. El pscomando para obtener el PID primario del PID primario es:
PPPID=`ps h -o ppid= $PPID`
pero necesitamos el nombre del comando, no el pid, así que llamamos
P_COMMAND=`ps h -o %c $PPPID`
ahora solo necesitamos probar el resultado para "cron"
Esto funciona solo para Linux ps. Para MacOS (así como Linux, tal vez * BSD también), puede usar el siguiente P_COMMAND:P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
mdd
1
Funciona en FreeBSD o en 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
Puede ir tan lejos en el árbol de procesos como lo desee.
No hay una respuesta autorizada, pero las variables prompt ( $PS1) y terminal ( $TERM) son bastante decentes aquí. Algunos sistemas se configuran TERM=dumbmientras que la mayoría lo deja vacío, por lo que solo buscaremos:
if["${TERM:-dumb}$PS1"!="dumb"];then
echo "This is not a cron job"fi
El código anterior sustituye la palabra "tonto" cuando no hay valor para $TERM. Por lo tanto, el condicional se activa cuando no hay $TERMo $TERMse establece en "tonto" o si la $PS1variable no está vacía.
He probado esto en Debian 9 ( TERM=), CentOS 6.4 y 7.4 ( TERM=dumb) y FreeBSD 7.3 ( TERM=).
ps
?ps
está bastante mal documentado (especialmente la versión de Linux que admite varios estilos de sintaxis diferentes) y la página de manual es aún más densa y críptica que la mayoría de las herramientas. Sospecho que la mayoría de las personas ni siquiera se dan cuenta de cuán útil y versátilps
puede ser una herramienta .Respuestas:
No soy consciente de que
cron
hace algo en su entorno por defecto que puede ser útil aquí, pero hay un par de cosas que podría hacer para obtener el efecto deseado.1) Haga un enlace fijo o suave al archivo de script, de modo que, por ejemplo,
myscript
ymyscript_via_cron
apunte al mismo archivo. A continuación, puede probar el valor$0
dentro del script cuando desea ejecutar u omitir condicionalmente ciertas partes del código. Pon el nombre apropiado en tu crontab y listo.2) Agregue una opción al script y establezca esa opción en la invocación crontab. Por ejemplo, agregue una opción
-c
, que le dice al script que ejecute u omita las partes apropiadas del código, y agregue-c
al nombre del comando en su crontab.Y, por supuesto, cron puede establecer variables de entorno arbitrarias, por lo que podría poner una línea como
RUN_BY_CRON="TRUE"
en su crontab y verificar su valor en su script.fuente
Los scripts ejecutados desde cron no se ejecutan en shells interactivos. Tampoco los scripts de inicio. La diferencia es que los shells interactivos tienen STDIN y STDOUT unidos a un tty.
Método 1: verifique si
$-
incluye lai
bandera.i
está configurado para shells interactivos.Método 2: el cheque
$PS1
está vacío.referencia: http://techdoc.kvindesland.no/linux/gnubooks/bash/bashref_54.html
Método 3: prueba tu tty. no es tan confiable, pero para trabajos cron simples debería estar bien, ya que cron no asigna por defecto un tty a un script.
Tenga en cuenta que, sin embargo, puede forzar el uso de un shell interactivo
-i
, pero probablemente lo sepa si lo hiciera ...fuente
bash
tengo acceso tiene $ -, al igual quedash
yksh
. incluso las conchas restringidas en Solaris lo tienen. ¿Qué plataforma estás tratando de usar cuando no funciona? ¿Quécase "$-" in *i*) echo true ;; *) echo false ;; esac
te muestra?Primero, obtenga el PID de cron, luego obtenga el PID principal (PPID) del proceso actual y compárelos:
Si su secuencia de comandos es iniciada por otro proceso que podría haber sido iniciado por cron, entonces puede volver a subir los PID principales hasta llegar a $ CRONPID o 1 (PID de init).
algo como esto, tal vez (Untested-But-It-Might-Work <TM>):
De Deian: esta es una versión probada en RedHat Linux
fuente
Si su archivo de script es invocado por
cron
y contiene un shell en la primera línea como#!/bin/bash
si necesitara encontrar el nombre padre-padre para su propósito.1)
cron
se invoca en el momento dado en sucrontab
, ejecutando un shell 2) el shell ejecuta su script 3) su script se está ejecutandoEl PID principal está disponible en bash como variable
$PPID
. Elps
comando para obtener el PID primario del PID primario es:pero necesitamos el nombre del comando, no el pid, así que llamamos
ahora solo necesitamos probar el resultado para "cron"
Ahora puedes probar en cualquier parte de tu script
¡Buena suerte!
fuente
P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
Funciona en FreeBSD o en Linux:
Puede ir tan lejos en el árbol de procesos como lo desee.
fuente
Una solución genérica a la pregunta "es mi salida un terminal o estoy ejecutando desde un script" es:
fuente
Un simple
echo $TERM | mail [email protected]
en cron me mostró que tanto en Linux como en AIX, cron parece estar configurado$TERM
como 'tonto'.Ahora, teóricamente, todavía puede haber terminales tontos reales, pero sospecho que para la mayoría de las ocasiones, eso debería ser suficiente ...
fuente
No hay una respuesta autorizada, pero las variables prompt (
$PS1
) y terminal ($TERM
) son bastante decentes aquí. Algunos sistemas se configuranTERM=dumb
mientras que la mayoría lo deja vacío, por lo que solo buscaremos:El código anterior sustituye la palabra "tonto" cuando no hay valor para
$TERM
. Por lo tanto, el condicional se activa cuando no hay$TERM
o$TERM
se establece en "tonto" o si la$PS1
variable no está vacía.He probado esto en Debian 9 (
TERM=
), CentOS 6.4 y 7.4 (TERM=dumb
) y FreeBSD 7.3 (TERM=
).fuente