スクリプトが手動で起動されるのではなく、cronによって起動されているかどうかを確認します


23

cronがプログラムを実行するときに設定する変数はありますか?スクリプトがcronで実行される場合、一部をスキップしたいと思います。それ以外の場合は、それらのパーツを呼び出します。

Bashスクリプトがcronによって開始されたかどうかを知るにはどうすればよいですか?


なぜ私たちだけじゃないのps
テルドン


@terdon:たぶんpsかなり文書化されていないため(特に、いくつかの異なる構文スタイルをサポートするLinuxのバージョン)、マニュアルページはほとんどのツールよりも密度が高く、不可解です。ほとんどの人は、このツールpsがどれほど便利で多用途であるかを認識さえしていないと思います。
cas

回答:


31

cronここで使用できるデフォルトの環境に対して何もしないことはわかりませんが、目的の効果を得るためにできることがいくつかあります。

1)たとえば、同じファイルmyscriptmyscript_via_cron指すように、スクリプトファイルへのハードリンクまたはソフトリンクを作成します。その後$0、コードの特定の部分を条件付きで実行したり省略したりするときに、スクリプト内の値をテストできます。crontabに適切な名前を入力すると、設定が完了します。

2)スクリプトにオプションを追加し、crontab呼び出しでそのオプションを設定します。たとえば、オプション-cを追加-cして、コードの適切な部分を実行または省略するようスクリプトに指示し、crontabのコマンド名に追加します。

そしてもちろん、cron 任意の環境変数を設定できるためRUN_BY_CRON="TRUE"、crontabのような行を追加して、スクリプトでその値を確認するだけで済みます。


7
RUN_BY_CRON = trueの+1
cas

casの回答は非常にうまく機能しており、他のあらゆるものにも使用できます。
Deian

19

cronから実行されるスクリプトは、対話型シェルでは実行されません。起動スクリプトもありません。違いは、対話型シェルのttyにSTDINとSTDOUTが接続されていることです。

方法1:フラグが$-含まれているかどうかを確認しiます。 i対話型シェルに設定されます。

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

方法2:チェック$PS1は空です。

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

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

方法3:ttyをテストします。そうではありません信頼性が、cronのは、デフォルトでスクリプトに端末を割り当てないような単純なcronジョブのためにあなたは、[OK]をする必要があります。

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

ただし、を使用してインタラクティブシェルを強制することはできますが-i、おそらくこれを実行している場合は知っているでしょう...


1
systemdによってスクリプトが開始されたかどうかを確認する場合、$ PS1コマンドは機能しないことに注意してください。$
-one

1
ウィニペグ大学のリンクが壊れています。
WinEunuuchs2Unix 16

1
@TimKennedyどういたしまして...エドモントンから:)
WinEunuuchs2Unix

'case "$-" in'は、bashスクリプトでは機能しないようです。
ホバディー

@Hobadee -すべてのbash私が持っている$へのアクセス権を持っている-などを行うdashksh。Solarisの制限付きシェルにもあります。動作しないプラットフォームで使用しようとしているプラ​​ットフォームは何ですか?何をcase "$-" in *i*) echo true ;; *) echo false ;; esac示していますか?
ティムケネディ

7

まず、cronのPIDを取得し、次に現在のプロセスの親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によって開始された可能性のある別のプロセスによってスクリプトが開始された場合、$ CRONPIDまたは1(initのPID)に到達するまで、親PIDに戻ることができます。

次のようなものかもしれません(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=1
done

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 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では、cronはシェルを開始し、シェルはスクリプトを実行します。スクリプトはそれ自体が別のシェルを開始します。したがって、スクリプトの親pidはcronのpidではありません。
16

4

スクリプトファイルが起動さcronれ、最初の行にシェルが含まれている#!/bin/bash場合、目的に合わせて親と親の名前を見つける必要があります。

1)cronで指定された時間に呼び出され、crontabシェルを実行します2)シェルがスクリプトを実行します3)スクリプトが実行されています

親PIDは変数としてbashで利用可能です$PPIDps親PIDの親PIDを取得するためのコマンドは次のとおりです。

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

しかし、pidではなくコマンドの名前が必要なので、

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

「cron」の結果をテストするだけです

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

スクリプトのどこでもテストできるようになりました

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

がんばろう!


これは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

必要に応じてプロセスツリーを上に移動できます。


1

「私の出力は端末か、スクリプトから実行していますか」という質問に対する一般的な解決策は次のとおりです。

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

0

echo $TERM | mail me@domain.comcron の簡単な説明から、LinuxとAIXの両方で、cron $TERMが「ダム」に設定されているように見えることがわかりました。

理論的にはまだ実際のダム端末が存在する可能性がありますが、ほとんどの場合、それで十分であると思われます...


0

正式な答えはありませんが、プロンプト($PS1)およびターミナル($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=)でテストしました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.