Vérifiez si le script est démarré par cron, plutôt qu'appelé manuellement
23
Existe-t-il une variable définie par cron lors de l'exécution d'un programme? Si le script est exécuté par cron, je voudrais ignorer certaines parties; sinon invoquer ces parties.
Comment savoir si le script Bash est démarré par cron?
@terdon: probablement parce qu'il psest assez mal documenté (en particulier la version de Linux qui prend en charge plusieurs styles de syntaxe différents) et la page de manuel est encore plus dense et cryptée que la plupart des outils. Je soupçonne que la plupart des gens ne réalisent même pas à quel point un outil pspeut être utile et polyvalent .
cas
Réponses:
31
Je ne suis pas conscient que cela cronfasse quoi que ce soit par défaut à son environnement qui puisse être utile ici, mais il y a quelques choses que vous pourriez faire pour obtenir l'effet souhaité.
1) Créez un lien physique ou logiciel vers le fichier de script, de sorte que, par exemple, myscriptet myscript_via_cronpointez vers le même fichier. Vous pouvez ensuite tester la valeur de l' $0intérieur du script lorsque vous souhaitez exécuter conditionnellement ou omettre certaines parties du code. Mettez le nom approprié dans votre crontab, et vous êtes prêt.
2) Ajoutez une option au script et définissez cette option dans l'invocation crontab. Par exemple, ajoutez une option -c, qui indique au script d'exécuter ou d'omettre les parties appropriées du code, et ajoutez -cau nom de la commande dans votre crontab.
Et bien sûr, cron peut définir des variables d'environnement arbitraires, vous pouvez donc simplement mettre une ligne comme RUN_BY_CRON="TRUE"dans votre crontab, et vérifier sa valeur dans votre script.
la réponse de cas fonctionne très bien et peut être utilisée pour autre chose aussi
Deian
19
Les scripts exécutés à partir de cron ne sont pas exécutés dans des shells interactifs. Les scripts de démarrage ne le sont pas non plus. La différenciation est que les shells interactifs ont STDIN et STDOUT attachés à un tty.
Méthode 1: vérifiez si $-inclut le idrapeau. iest défini pour les shells interactifs.
Méthode 3: testez votre tty. ce n'est pas aussi fiable, mais pour les tâches cron simples, vous devriez être d'accord, car cron n'alloue pas de tty par défaut à un script.
Gardez à l'esprit que vous pouvez cependant forcer l'utilisation d'un shell interactif -i, mais vous seriez probablement au courant si vous faisiez cela ...
Notez que la commande $ PS1 ne fonctionne pas lors de la vérification si le script est démarré par systemd ou non. the $ - one does
mveroone
1
Votre lien avec l'Université de Winnipeg est rompu.
WinEunuuchs2Unix
1
@TimKennedy Vous êtes les bienvenus .... d'Edmonton :)
WinEunuuchs2Unix
'case "$ -" in' ne semble pas fonctionner dans les scripts bash.
Hobadee
@Hobadee - tout ce à quoi bashj'ai accès a $ -, tout comme dashet ksh. même les obus restreints de Solaris l'ont. Quelle plateforme essayez-vous de l'utiliser là où cela ne fonctionne pas? Qu'est-ce que ça case "$-" in *i*) echo true ;; *) echo false ;; esacvous montre?
Tim Kennedy
7
Tout d'abord, obtenez le PID de cron, puis obtenez le PID parent du processus en cours (PPID) et comparez-les:
CRONPID=$(ps ho %p -C cron)
PPID=$(ps ho %P -p $$)if[ $CRONPID -eq $PPID ];then echo Cron is our parent.;fi
Si votre script est démarré par un autre processus qui pourrait avoir été démarré par cron, alors vous pouvez remonter les PID parents jusqu'à ce que vous atteigniez $ CRONPID ou 1 (PID d'init).
quelque chose comme ça, peut-être (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: Ceci est une version testée sur 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}"
Sous Solaris, cron démarre un shell et le shell exécute le script, qui lui-même démarre un autre shell. Donc, le pid parent dans le script n'est pas le pid de cron.
ceving
4
Si votre fichier de script est invoqué par cronet qu'il contient un shell dans la première ligne, comme #!/bin/bashvous devez trouver le nom parent-parent pour votre objectif.
1) cronest invoqué à un moment donné dans votre crontab, exécutant un shell 2) le shell exécute votre script 3) votre script est en cours d'exécution
Le PID parent est disponible en bash en tant que variable $PPID. La pscommande pour obtenir le PID parent du PID parent est:
PPPID=`ps h -o ppid= $PPID`
mais nous avons besoin du nom de la commande, pas du pid, donc nous appelons
P_COMMAND=`ps h -o %c $PPPID`
il nous suffit maintenant de tester le résultat pour "cron"
Cela ne fonctionne que pour Linux ps. Pour MacOS (ainsi que Linux, peut-être aussi * BSD), vous pouvez utiliser le P_COMMAND suivant:P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
mdd
1
Fonctionne sur FreeBSD ou sur 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
Vous pouvez aller aussi loin que vous le souhaitez dans l'arborescence des processus.
Un simple echo $TERM | mail [email protected]dans cron m'a montré que sous Linux et AIX, cron semble réglé $TERMsur 'muet'.
Maintenant, théoriquement, il peut toujours y avoir de vrais terminaux stupides, mais je soupçonne que pour la plupart des occasions, cela devrait suffire ...
Il n'y a pas de réponse faisant autorité, mais les variables prompt ( $PS1) et terminal ( $TERM) sont plutôt correctes ici. Certains systèmes sont définis TERM=dumbtandis que la plupart le laissent vide, nous allons donc simplement vérifier:
if["${TERM:-dumb}$PS1"!="dumb"];then
echo "This is not a cron job"fi
Le code ci-dessus remplace le mot "muet" lorsqu'il n'y a pas de valeur pour $TERM. Par conséquent, le conditionnel se déclenche lorsqu'il n'y a pas $TERMou $TERMest défini sur "muet" ou si la $PS1variable n'est pas vide.
J'ai testé cela sur Debian 9 ( TERM=), CentOS 6.4 & 7.4 ( TERM=dumb) et FreeBSD 7.3 ( TERM=).
ps
?ps
est assez mal documenté (en particulier la version de Linux qui prend en charge plusieurs styles de syntaxe différents) et la page de manuel est encore plus dense et cryptée que la plupart des outils. Je soupçonne que la plupart des gens ne réalisent même pas à quel point un outilps
peut être utile et polyvalent .Réponses:
Je ne suis pas conscient que cela
cron
fasse quoi que ce soit par défaut à son environnement qui puisse être utile ici, mais il y a quelques choses que vous pourriez faire pour obtenir l'effet souhaité.1) Créez un lien physique ou logiciel vers le fichier de script, de sorte que, par exemple,
myscript
etmyscript_via_cron
pointez vers le même fichier. Vous pouvez ensuite tester la valeur de l'$0
intérieur du script lorsque vous souhaitez exécuter conditionnellement ou omettre certaines parties du code. Mettez le nom approprié dans votre crontab, et vous êtes prêt.2) Ajoutez une option au script et définissez cette option dans l'invocation crontab. Par exemple, ajoutez une option
-c
, qui indique au script d'exécuter ou d'omettre les parties appropriées du code, et ajoutez-c
au nom de la commande dans votre crontab.Et bien sûr, cron peut définir des variables d'environnement arbitraires, vous pouvez donc simplement mettre une ligne comme
RUN_BY_CRON="TRUE"
dans votre crontab, et vérifier sa valeur dans votre script.la source
Les scripts exécutés à partir de cron ne sont pas exécutés dans des shells interactifs. Les scripts de démarrage ne le sont pas non plus. La différenciation est que les shells interactifs ont STDIN et STDOUT attachés à un tty.
Méthode 1: vérifiez si
$-
inclut lei
drapeau.i
est défini pour les shells interactifs.Méthode 2: le chèque
$PS1
est vide.référence: http://techdoc.kvindesland.no/linux/gnubooks/bash/bashref_54.html
Méthode 3: testez votre tty. ce n'est pas aussi fiable, mais pour les tâches cron simples, vous devriez être d'accord, car cron n'alloue pas de tty par défaut à un script.
Gardez à l'esprit que vous pouvez cependant forcer l'utilisation d'un shell interactif
-i
, mais vous seriez probablement au courant si vous faisiez cela ...la source
bash
j'ai accès a $ -, tout commedash
etksh
. même les obus restreints de Solaris l'ont. Quelle plateforme essayez-vous de l'utiliser là où cela ne fonctionne pas? Qu'est-ce que çacase "$-" in *i*) echo true ;; *) echo false ;; esac
vous montre?Tout d'abord, obtenez le PID de cron, puis obtenez le PID parent du processus en cours (PPID) et comparez-les:
Si votre script est démarré par un autre processus qui pourrait avoir été démarré par cron, alors vous pouvez remonter les PID parents jusqu'à ce que vous atteigniez $ CRONPID ou 1 (PID d'init).
quelque chose comme ça, peut-être (Untested-But-It-Might-Work <TM>):
De Deian: Ceci est une version testée sur RedHat Linux
la source
Si votre fichier de script est invoqué par
cron
et qu'il contient un shell dans la première ligne, comme#!/bin/bash
vous devez trouver le nom parent-parent pour votre objectif.1)
cron
est invoqué à un moment donné dans votrecrontab
, exécutant un shell 2) le shell exécute votre script 3) votre script est en cours d'exécutionLe PID parent est disponible en bash en tant que variable
$PPID
. Laps
commande pour obtenir le PID parent du PID parent est:mais nous avons besoin du nom de la commande, pas du pid, donc nous appelons
il nous suffit maintenant de tester le résultat pour "cron"
Vous pouvez maintenant tester n'importe où dans votre script
Bonne chance!
la source
P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
Fonctionne sur FreeBSD ou sur Linux:
Vous pouvez aller aussi loin que vous le souhaitez dans l'arborescence des processus.
la source
Une solution générique à la question «ma sortie est-elle un terminal ou suis-je en train d'exécuter à partir d'un script» est:
la source
Un simple
echo $TERM | mail [email protected]
dans cron m'a montré que sous Linux et AIX, cron semble réglé$TERM
sur 'muet'.Maintenant, théoriquement, il peut toujours y avoir de vrais terminaux stupides, mais je soupçonne que pour la plupart des occasions, cela devrait suffire ...
la source
Il n'y a pas de réponse faisant autorité, mais les variables prompt (
$PS1
) et terminal ($TERM
) sont plutôt correctes ici. Certains systèmes sont définisTERM=dumb
tandis que la plupart le laissent vide, nous allons donc simplement vérifier:Le code ci-dessus remplace le mot "muet" lorsqu'il n'y a pas de valeur pour
$TERM
. Par conséquent, le conditionnel se déclenche lorsqu'il n'y a pas$TERM
ou$TERM
est défini sur "muet" ou si la$PS1
variable n'est pas vide.J'ai testé cela sur Debian 9 (
TERM=
), CentOS 6.4 & 7.4 (TERM=dumb
) et FreeBSD 7.3 (TERM=
).la source