スクリプトを手動で呼び出すのではなく、cronで始まることを確認してください。

スクリプトを手動で呼び出すのではなく、cronで始まることを確認してください。

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

Bashスクリプトがcronによって起動されたかどうかはどうすればわかりますか?

答え1

ここで利用可能な環境について基本的に何をするのかわかりませんが、目的の効果をcron得るためにできることがいくつかあります。

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

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

もちろんcronもあります。できる任意の環境変数を設定したら、crontabに1行を追加してRUN_BY_CRON="TRUE"スクリプトでその値を確認できます。

答え2

cron で実行されるスクリプトは、対話型シェルでは実行されません。起動スクリプトも同様です。違いは、対話型シェルがSTDINとSTDOUTをttyに追加することです。

方法1:フラグが$-含まれていることを確認してくださいii対話型シェルに設定します。

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

方法2:$PS1空であることを確認してください。

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

引用:

方法 3: tty をテストします。そうではない〜のように信頼できますが、単純なcronジョブの場合、cronはデフォルトでスクリプトにttyを割り当てないため、問題はありません。

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

強制対話型シェルを使用できることに注意してください-i。しかし、そうすれば、次の事実に気づくでしょう。

答え3

まず、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に戻ることができます。

おそらく次のようになります(テストされていませんが、動作する可能性があります<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}"

答え4

権威ある答えはありません。ここにある他の答えのいくつかは実際にcron環境と一致しようとしますが、これは難しい作業です。

CRON='in_cron'個人的には、私は上のようにcrontabに変数を設定しました。その後、次のようにテストできます。

if [ "$CRON" != "in_cron" ]; then
  echo "This is not a cron job"
fi

これにより、Interactive / nohup / sshとcronが明確に区別されますが、関連ユーザーのcrontabに変数を宣言する必要があります。 /etc/cron.dスクリプトの場合は、/etc/crontabに入れることができる必要があります(少なくとも私のDebian 12システムでは動作します)。


ターミナル($TERM)変数はシェルの「対話型」オプションフラグ(特殊パラメータ $-含むi)。一部のシステムでは設定されていますが、TERM=dumbほとんどは空白のままであるため、そのうちの1つを確認して対話型オプションフラグを確認します。

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

上記のコードは、値がない場合に「dumb」という単語を置き換えます$TERM。したがって、変数が存在しない場合、「dumb」に設定されている場合、または変数が空でない場合、またはifが$TERM最初の文字より前のすべての文字を削除している間にそれ自体と一致しない場合、条件が実行されます(noがなければ何も削除されません)。$TERM$PS1$-ii

私はこれをDebian 9、11&12(TERM=)、CentOS 6.4&7.4(TERM=dumb)、FreeBSD 7.3&&11.2()TERM=でテストしました。これはさらに含まれていますが、$PS1私のDebian 12システムのcronは何らかの方法でその変数を設定します。

少なくともDebian 12では、Interactive / nohupとcron / sshが区別されます。


端末名も確認できます。 Cronは通常(OK!)端末を割り当てていないので、次のことができます。ttyそしてPOSIX標準要件(ターミナルがない場合)not a tty出力に次のように表示する必要があります。

if [ "$(tty)" != "not a tty" ]; then
  echo "This is not a cron job"
fi

少なくともDebian 12では、インタラクティブとcron / ssh / nohupを区別します。


もう一つの答えマッチインタラクションについて言及しました( : > /dev/tty) 2>/dev/null

少なくともDebian 12では、これはInteractive / nohupをcron / sshと区別します。


端末を割り当てずにcronを使用する4番目の方法は、標準入力が開いているかどうかをテストすることです。を使用してこれを実行できますが、! [ -t 0 ]データをスクリプトにリンクすると誤った答えが得られます。

関連情報