Komut dosyasının el ile çağrılmak yerine cron tarafından başlatılıp başlatılmadığını kontrol edin


23

Bir program çalıştırıldığında cron'un ayarladığı herhangi bir değişken var mı? Senaryo cron tarafından çalıştırılıyorsa, bazı kısımları atlamak istiyorum; aksi takdirde bu parçaları çağırınız.

Bash komut dosyasının cron tarafından başlatıldığını nasıl bilebilirim?


Neden sadece biz değilsin ps?
terdon


@terdon: Muhtemelen psoldukça kötü bir şekilde belgelendiğinden (özellikle birkaç farklı sözdizimi stilini destekleyen Linux sürümü) ve man sayfası çoğu araçtan daha yoğun ve şifreli olduğundan. Çoğu insanın bir aracın ne kadar kullanışlı ve çok yönlü psolabileceğini bile anlamadığından şüpheleniyorum .
Cas

Yanıtlar:


31

cronVarsayılan olarak ortamına burada kullanılabilecek herhangi bir şey yapabileceğinin farkında değilim , ancak istediğiniz etkiyi elde etmek için yapabileceğiniz birkaç şey var.

1) sert veya yumuşak, böylece komut dosyasına bağlantı, örneğin, Make myscriptve myscript_via_cronaynı dosyaya gelin. $0Kodun belirli bölümlerini koşullu olarak çalıştırmak veya atlamak istediğinizde, betiğin içindeki değerini test edebilirsiniz . Crontab'ınıza uygun adı girin ve hazırsınız.

2) Komut dosyasına bir seçenek ekleyin ve bu seçeneği crontab çağrısında ayarlayın. Örneğin -c, betiğe kodun ilgili kısımlarını çalıştırmasını veya atlamasını söyleyen bir seçenek ekleyin -cve crontab'ınızdaki komut adına ekleyin .

Ve elbette, cron keyfi ortam değişkenlerini de ayarlayabilir, böylece RUN_BY_CRON="TRUE"crontab'ınızdaki gibi bir çizgi koyabilir ve betiğinizdeki değerini kontrol edebilirsiniz.


7
RUN_BY_CRON için 1 = true
cas

cas tarafından cevap çok iyi çalışıyor ve başka bir şey için de kullanılabilir
Deian

19

Cron'dan çalıştırılan komut dosyaları etkileşimli kabuklarda çalıştırılmaz. Başlangıç ​​komut dosyaları da değil. Farklılık, etkileşimli mermilerin STDIN ve STDOUT'un tty'ye bağlı olmasıdır.

Yöntem 1: çek eğer $-içerir ibayrağı. ietkileşimli kabukları için ayarlanır.

case "$-" in
    *i*)
        interactive=1
        ;;
    *)
        not_interactive=1
        ;;
esac

Yöntem 2: kontrol $PS1boş.

if [ -z "$PS1" ]; then
    not_interactive=1 
else
    interactive=1
fi

referans: http://techdoc.kvindesland.no/linux/gnubooks/bash/bashref_54.html

Yöntem 3: tty'nizi test edin. o kadar güvenilir değil , fakat basit cron işleri için tamam olmalı, çünkü cron varsayılan olarak bir betiğe tty ayırmaz.

if [ -t 0 ]; then
    interactive=1
else
    non_interactive=1
fi

Bununla birlikte, etkileşimli bir kabuğu kullanarak zorlayabileceğinizi unutmayın -i, ancak bunu yaparsanız büyük olasılıkla farkında olursunuz ...


1
Komut dosyasının sistem tarafından başlatılıp başlatılmadığını kontrol ederken $ PS1 komutunun çalışmadığını unutmayın. $ - bir yapar
mveroone

1
Winnipeg University bağlantınız koptu.
WinEunuuchs2Unix

1
@TimKennedy Rica ederim .... Edmonton'dan :)
WinEunuuchs2Unix

'case "$ -" in' bash betiğinde çalışıyor gibi görünmüyor.
Hobadee

@Hobadee - her bashi sahiptir $ erişebilir - gibi yapmak dashve ksh. Solaris'teki sınırlı mermilerde bile var. Hangi platformu çalışmadığı yerlerde kullanmaya çalışıyorsunuz? case "$-" in *i*) echo true ;; *) echo false ;; esacSize ne gösterir?
Tim Kennedy,

7

Öncelikle cron PID'sini alın, ardından geçerli işlemin üst PID'sini (PPID) alın ve karşılaştırın:

CRONPID=$(ps ho %p -C cron)
PPID=$(ps ho %P -p $$)
if [ $CRONPID -eq $PPID ] ; then echo Cron is our parent. ; fi

Komut dosyanız cron tarafından başlatılmış olabilecek başka bir işlemle başlatılmışsa, $ CRONPID veya 1 (init'in PID) değerine gelinceye kadar ana PID'lerinizi geri alabilirsiniz.

bunun gibi bir şey, belki (Denenmemiş-Ama-Olabilir-İş <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=1
done

Deian'dan: Bu, RedHat Linux'ta test edilmiş bir versiyondur

# 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 CPID
        for CRONPID in $CRONPIDS ; do
                [ $CRONPID -eq $CPID ] && CRON_IS_PARENT=1
                # we could leave earlier but it's okay like that too
        done
done

# now do whatever you want with the information
if [ "$CRON_IS_PARENT" == "1" ]; then
        CRON_CALL="Y"
else
        CRON_CALL="N"
fi

echo "CRON Call: ${CRON_CALL}"

1
Solaris'te cron bir kabuk başlatır ve kabuk kendi kendine başka bir kabuk başlatan betiği çalıştırır. Bu yüzden senaryoda ana pid cron değil.
16'da

4

Komut dosyanız tarafından çağrılırsa cronve #!/bin/bashsizin gibi ilk satırda bir kabuk içeriyorsa , amacınız için ebeveyn-ebeveyn adını bulmanız gerekir.

1) cronsizin için belirtilen zamanda çağrılır, crontabbir kabuk yürütme 2) kabuk komut dosyanızı çalıştırır 3) komut dosyası çalışıyor

Üst PID değişken olarak bash olarak bulunur $PPID. psKomut PID olan ebeveynin ebeveyn PıD'YI almak için:

PPPID=`ps h -o ppid= $PPID`

ama emir yerine emir komutunun ismine ihtiyacımız var.

P_COMMAND=`ps h -o %c $PPPID`

Şimdi sadece "cron" için sonucu test etmemiz gerekiyor

if [ "$P_COMMAND" == "cron" ]; then
  RUNNING_FROM_CRON=1
fi

Şimdi betiğinizdeki herhangi bir yeri test edebilirsiniz

if [ "$RUNNING_FROM_CRON" == "1" ]; then
  ## do something when running from cron
else
  ## do something when running from shell
fi

İyi şanslar!


Bu sadece Linux ps için çalışır. MacOS için (Linux gibi, belki * BSD de), aşağıdaki P_COMMAND'ı kullanabilirsiniz:P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
mdd

1

FreeBSD veya Linux'ta çalışır:

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

İşlem ağacına istediğiniz kadar gidebilirsiniz.


1

"Çıktım bir terminaldir veya bir komut dosyasından çalıştırıyorum" sorusuna genel bir çözümdür:

( : > /dev/tty) && dev_tty_good=y || dev_tty_good=n

0

Bir echo $TERM | mail me@domain.comcron basit bana hem Linux hem de AIX'de cronun $TERM'aptal' gibi göründüğünü gösterdi .

Şimdi teorik olarak hala aptalca terminaller olabilir, ama çoğu durumda bunun yeterli olması gerektiğinden şüpheliyim ...


0

Yetkili bir cevap yok, ancak prompt ( $PS1) ve terminal ( $TERM) değişkenleri burada oldukça iyi. Bazı sistemler TERM=dumbçoğu boş bıraktığında ayarlanır , bu yüzden ikisini de kontrol ederiz:

if [ "${TERM:-dumb}$PS1" != "dumb" ]; then
  echo "This is not a cron job"
fi

Yukarıdaki kod, değeri olmadığında "aptal" kelimesini değiştirir $TERM. Bu nedenle, koşulsuz, "aptal" olarak ayarlanmadığında $TERMveya $TERMayarlanmadığında veya $PS1değişken boş olmadığında patlar .

Bunu Debian 9 ( TERM=), CentOS 6.4 & 7.4 ( TERM=dumb) ve FreeBSD 7.3 ( TERM=) üzerinde test ettim .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.