🐈

cronで任意の分単位で実行する・エスケープを回避する

2022/11/25に公開

動機

cronで16分ごとに実行したい機会があったので方法を調べました。その際、cronの記法のエスケープ周りでハマっていたのですが、回避法も見つけたので書きます。

やったこと

cronの時間設定を自由にする

こちらを参考にしました。

https://qiita.com/cheeseNA/items/d6bd70982fd3777538f3

60の約数であれば、例えば 0/3 * * * * などで設定できますが、そうでない場合はできません。

↑で紹介されている方法として、毎分実行して、その時刻をエポック分に変換してインターバルの倍数かどうかを判定します。

以下の場合、eposhを秒にして(%s)、分にして(/60)から 16で割ってあまりが 0 なら echo "hello"を実行します。

cron
* * * * * test $[($(date +\%s))/60\%16] -eq 0 && echo "hello"

エスケープするが・・・ハマる

上記では、%の部分が \%と書いてありますが、これはcronでのエスケープです。しかし、私の環境(Ubuntu)では動作しませんでした。cronの記述は何かとハマりますね・・・。

https://stackoverflow.com/questions/23229682/special-escaping-for-crontab

こちらの方法を参考にして、シェルスクリプト内で判定することにしました。気づいたらああそうか、という感じですがハマっている間は思いつかないですよねー。

mycron.sh
interval=16

mod=$[($(date +%s)) / 60 % $interval]

if [ $mod -eq 0 ]; then
	echo "hello"
fi

最終的にcrontab -e にはこう書きます。

cron
* * * * * bash path/to/mycron.sh

まとめ

  • cronで自由にインターバル時間を決めて実行することができた
  • shellで呼び出すようにして、cronの記述でハマるのを避けられた

(余談:Amazon EventBridgeなら楽なはずだが)

EventBridgeを使うとrate()で自由にインターバル時間を決められるのですが、今回はpythonを実行してboto3の最新版を使いたいけどそれもLambdaの設定が面倒なのでローカルでcronしようという状況でした。

Discussion