rcmdnk's blog

Amazon | CRON.: El encuentro de una especie humana de la última era glaciar. (Spanish Edition) [Kindle edition] by Alejandro Naya | Science Fiction | Kindleストア

cronジョブでは実行時に環境変数が最小限の 環境変数しか設定されないため、例えばPATHとかも最小限で 普段使っているコマンドが使えなかったりします。

その場合には走らせるcronジョブのスクリプトの中で設定するか、 もしくはcronジョブの定義で変数を設定してあげる必要があります。

Sponsored Links

デフォルトの環境変数

$ cat a.sh
#!/bin/bash
env > $HOME/cron.log

こんな感じのスクリプトを作ってchmod 755しておいて、 crontab -e

39 * * * * $HOME/a.sh

と設定し(39は分、すぐに実行できる時間に)調べてみます。

CentOS 7だと

XDG_SESSION_ID=<xxx>
SHELL=/bin/sh
USER=<user>
PATH=/usr/bin:/bin
_=/usr/bin/env
PWD=/home/<user>
LANG=en_US.UTF-8
HOME=/home/<user>
SHLVL=2
LOGNAME=<user>
XDG_RUNTIME_DIR=/run/user/<uid>

macOS Catalinaだと

SHELL=/bin/sh
USER=<user>
PATH=/usr/bin:/bin
_=/usr/bin/env
PWD=/Users/<user>
HOME=/Users/<user>
SHLVL=2
LOGNAME=<user>

みたいな感じで基本的にUSERHOMEPATHくらいです。 PATH/usr/bin:/binと必要最小限のものしか通ってません。

このまま普段使っているシェルスクリプトとかをcronジョブに設定すると 中で使っているコマンドにPATHが通って無くて失敗したりします。

環境変数の設定

環境変数は、cronのジョブの定義をする前に変数設定を書いてあげるとそれを使ってくれます。

MY_VAL=xxx
39 * * * * $HOME/a.sh

とすればMY_VAL=xxxが見れるはずです。

もし、

$ cat b.sh
#!/bin/bash
env > $HOME/cron2.log

を用意して

MY_VAL=xxx
39 * * * * $HOME/a.sh
MY_VAL2=yyy
39 * * * * $HOME/b.sh

みたいなcronの定義をすると cron.logの方にはMY_VAL=xxxだけが出て、cron2.logの方にはMY_VAL=xxxMY_VAL2=yyyの両方が出てきます。

上から順に見ていき、ジョブの定義の時点でどういうものが設定されているか、 がそのまま渡される形です。

ちょっと注意が必要なのは、cronの定義はシェルスクリプトではない、ということです。

シェルスクリプト(もしくは普段のシェル上での作業)で環境変数を設定するには exportが必要で、使わないとただのシェル変数でサブプロセスに引き継がれません。

一方、cronの定義では上の様なたんなるX=Yの形で環境変数を設定することになります。 exportとかは使えません。

また、前に定義した変数を使って変数を定義することはできません。

MY_VAL=xxx
MY_VAL2=$MY_VAL

とかしてもMY_VAL2には$MY_VALという文字列そのものが設定されてしまいます。

一方、ジョブの定義では使えて

COMMAND_PATH=/path/to/command
39 * * * * $COMMAND_PATH/my_command

みたいなことはちゃんと$COMMAND_PAHTを展開してくれます。 もちろん、my_commandの中でも$COMMAND_PATHを使えます。

cronの特殊な変数

cronで良く設定する変数としては

[email protected]

の様にMAILTOを設定して出力をメールに送るものだと思います。 設定しないと出力はローカルマシンの該当ユーザーのメールに送られます。

勿論これを設定しておけばこの値をスクリプトの中で使うことも出来ます。

もう一つ、SHELLの設定。 上を見ても設定されているのがわかりますが、このシェルでコマンドが実行されます。 通常/bin/shがデフォルトなので、普段/bin/bashを使ってる感覚でコマンドを定義すると 失敗することがあります。

出力をファイルに出そうとして>& logとかしたら>&が使えなかった、とか。

なるべくcronジョブに設定するものは専用のスクリプトを用意して、 出力とかも全部中で処理するようにすると、 外側でのSHELLの影響を受けなくなるので良いかとは思います。

cronジョブの書き方

ついでによくわからなくなるcronジョブの書き方のまとめ。

ジョブの定義としてはユーザー単位で定義する場合には通常crontab -eで定義ファイルを開いて編集。 システムとして登録する場合には /etc/cron.d/の中に定義ファイルを配置。

どちらも書き方は同じようなものですが、基本的に

<分> <時> <日> <月> <曜日> my command

と書いていつ実行するか、を定義します。 後ろに実行コマンドを書きますが、/etc/cron.d/の場合にはその前にユーザーを指定する必要があります。

<分> <時> <日> <月> <曜日> user my command...

*を指定すれば全ての場合、になります。

10 * * * *

なら毎時10分に実行。

10 1 * * *

なら毎日1時10分に実行。

曜日、は0~7で0と7が日曜、間の1から6が月曜から土曜になります。

月と曜日に関してはJanSunなど名前の3文字でも指定できます(大文字小文字は関係なし)。

また、1時間のうちに複数回実行したいなら

10,40 * * * *

の様にコンマで区切って複数指定することが出来ます。

10 1-3 * * *

の様にハイフンでつなぐと、上野場合は1時、2時、3時の全てで10分にじっこうすることになります。

または、

*/10 * * * *

の様な書き方をすると10分ごとに実行してくれます。

もしくは

15-35/10 * * * *

とかすると、 15分、25分、35分に実行されます。(15-35分の中で10分おき)

もし、日にちと曜日の両方を*以外で指定していた場合、どちらかが満たされている場合にORで実行されます。 *が全部を表すのに使うので、指定するとANDになりそうなものですがちょっと注意が必要です。

これ以外にも 以下の様にリブート時を指定したり、毎時、などを簡略化してかける方法もあります。

@reboot         Run once, at startup.
@yearly         Run once a year, "0 0 1 1 *".
@annually       (same as @yearly)
@monthly        Run once a month, "0 0 1 * *".
@weekly         Run once a week, "0 0 * * 0".
@daily          Run once a day, "0 0 * * *".
@midnight       (same as @daily)
@hourly         Run once an hour, "0 * * * *".

%をエスケープしないといけない

cronジョブの定義で%は特殊文字となり それ以降の文字列がコマンドへの標準入力として使われる様になります。

コマンドの中で%を使いたい場合には\でエスケープする必要があります。

10 * * * * date +%s

だと

date + < <(echo s)

というコマンドを実行するのと同じになります。

この場合は何も出力されないだけですが、普通はなにか変なエラーになるかと。

正しくやりたい通りにするためには

10 * * * * date +\%s

の様に%をエスケープしてやる必要があります。

Sponsored Links
Sponsored Links

« Macで`open`コマンドがLSOpenURLsWithRole() failed with error -600 GoogleスライドはPowerPointの代わりになるか »