プログラムの実行時にcronが設定する変数はありますか?スクリプトがcronで実行されている場合は、一部をスキップします。それ以外の場合は、それらの部分を呼び出します。
Bashスクリプトがcronによって起動されているかどうかを確認するにはどうすればよいですか?
ここではcron
がデフォルトで環境に役立つことを認識していませんが、目的の効果を得るためにできることがいくつかあります。
1)スクリプトファイルへのハードリンクまたはソフトリンクを作成して、たとえば、myscript
とmyscript_via_cron
が同じファイルを指すようにします。次に、条件付きでコードを実行したり、コードの特定の部分を省略したりするときに、スクリプト内で$0
の値をテストできます。適切な名前をcrontabに入力すれば、設定は完了です。
2)スクリプトにオプションを追加し、crontab呼び出しでそのオプションを設定します。たとえば、スクリプトにコードの適切な部分を実行または省略するように指示するオプション-c
を追加し、crontabのコマンド名に-c
を追加します。
そしてもちろん、cron canは任意の環境変数を設定するので、RUN_BY_CRON="TRUE"
のような行をcrontabに入れて、スクリプトでその値を確認できます。
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をテストします。 asは信頼できませんが、cronはデフォルトでスクリプトにttyを割り当てないため、単純なcronジョブの場合は問題ありません。
if [ -t 0 ]; then
interactive=1
else
non_interactive=1
fi
ただし、-i
を使用してインタラクティブシェルを強制することはできますが、これを実行しているかどうかはおそらく気になるでしょう...
まず、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(初期の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}"
スクリプトファイルがcron
によって呼び出され、そのファイルの最初の行に#!/bin/bash
のようなシェルが含まれている場合は、目的に応じて親と親の名前を見つける必要があります。
1)cron
がcrontab
で指定された時間に呼び出され、シェルを実行する2)シェルがスクリプトを実行する3)スクリプトが実行されている
親PIDは、変数$PPID
としてbashで使用できます。親PIDの親PIDを取得するps
コマンドは次のとおりです。
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
幸運を!
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
プロセスツリーは必要なだけ上に移動できます。
「私の出力はターミナルですか、それともスクリプトから実行していますか」という質問に対する一般的な解決策は次のとおりです。
( : > /dev/tty) && dev_tty_good=y || dev_tty_good=n
誰も言及していない問題があります。 sshを使用してリモートコンピューターからスクリプトを実行すると、ほとんどのテストが失敗します。
ssh [email protected] ./SmartHome.sh
次に(たとえば)[-t 0]および(:>/dev/tty)と$ TERMはすべて間違っていることを示します(OK、実際にはすべて正しいですが、必要なものを示していません)。
したがって、最も単純なユニバーサルソリューションは、2で最も支持されている回答で述べたように、引数を指定してcronからスクリプトを呼び出すことです。その後、他の呼び出しはすべて手動実行と見なされます。私は-(ただし、何でもかまいません)をcron呼び出しの最初の引数として使用し、スクリプトで確認します。
[ "$1" == "-" ] && shift || Run_Manually=1
シンプルな echo $TERM | mail [email protected]
cronでLinuxとAIXの両方でcronが$TERM
を「ダム」に。
今理論的にはまだ実際のダム端末が残っているかもしれませんが、ほとんどの場合、それで十分でしょう...
信頼できる回答はありませんが、プロンプト($PS1
)とターミナル($TERM
)の変数は、シェルの「インタラクティブ」オプションフラグ( 特別なパラメーター と同様、かなりまともです。 $-
にはi
が含まれています)。一部のシステムはTERM=dumb
を設定しますが、ほとんどの場合は空のままにします。そのため、どちらかを確認し、インタラクティブオプションフラグも確認します。
if [ "${TERM:-dumb}$PS1$-" != "dumb${-#*i}" ]; then
echo "This is not a cron job"
fi
上記のコードは、$TERM
に値がない場合、Wordの「ダム」を置き換えます。したがって、$TERM
または$TERM
が「ダム」に設定されていない場合、または$PS1
変数が空でない場合、または$-
がそれ自体と一致しない場合に、条件が発生します。最初のi
までのすべての文字を削除します(i
がない場合は何も削除されません)。
または、端末名を確認することもできます。通常、cronは(これを確認してください!)端末を割り当てません。そのため、 tty
と POSIX標準マンデート を実行できます(実際にない場合)端末)出力でnot a tty
と言う必要があります。
if [ "$(tty)" != "not a tty" ]; then
echo "This is not a cron job"
fi
端末を割り当てないcronを利用する別の方法は、標準入力が開いているかどうかをテストすることです。これは! [ -t 0 ]
を使用して行うことができますが、データをスクリプトにパイプ処理している場合、これは不適切な回答になります。
Debian 9と11(TERM=
、ttyはnot a tty
)、CentOS 6.4&7.4(TERM=dumb
、ttyはnot a tty
)、およびFreeBSD 7.3で両方のオプションをテストしました&& 11.2(TERM=
、ttyはnot a tty
)。