たとえばrootのcrontabにこんなジョブを書いたとする。 毎分「neko」を今日の日付がついたログファイルに書き込むだけのジョブ。
# crontab -l MAILTO='自分のメールアドレス' MAILFROM='root@ghana.infra.xyz' * * * * * echo "neko" > /var/log/test.`date +%Y%m%d`.log
設定してcronのログを眺めていると、1分以内にこんなログが流れてくる。
# tailf /var/log/cron Aug 16 12:00:01 localhost CROND[1934]: (root) CMD (echo "neko" > /var/log/test.`date +)
ログを見ると「echo "neko" > /var/log/test.`date +」なので+の後ろが全部切れてる?! そしてさらにこんなメールが自分のアドレスに飛んでくる。
From: Cron Daemon <root@ghana.infra.xyz> To: 自分のメールアドレス Subject: Cron <root@ghana> echo "neko" > /var/log/test.`date + (中略) /bin/sh: -c: line 0: unexpected EOF while looking for matching ``' /bin/sh: -c: line 1: syntax error: unexpected end of file
どういうこと・・・?もしかしてなんかコマンド書き間違えた?と思って、 まったく同じコマンドをcronじゃなくて直に叩いてみるとそっちは上手くいく。
# echo "neko" > /var/log/test.`date +%Y%m%d`.log # ls /var/log/test.20180816.log /var/log/test.20180816.log ←ちゃんとファイルできてる
「cron unexpected EOF while looking for matching」とかでググると、 %をエスケープしろよハゲみたいな記事が多く出てくるので man crontabしてみたけどそんなことは書いてない。
うーん・・・?と思ったがman crontabだとセクション1(crontabコマンド)のmanpageが出てくるので、 そっちじゃなくてman 5 crontabで、セクション5(crontabのファイルフォーマット)のmanpageを確認。
書いてあった!
「第6」フィールド (行の残りの部分) には実行されるコマンドを指定する。 コマンド中にパーセント記号 (%) がバックスラッシュ () によってエスケープされずに置かれていると、改行文字に置き換えられ、最初に現れた % 以降の全てのデータは標準入力としてコマンドに送られる。
つまり、cron的には
* * * * * echo "neko" > /var/log/test.`date +%Y%m%d`.log
は%が改行に置き換えられちゃうので、
* * * * * echo "neko" > /var/log/test.`date + Y m d`.log
になっていた!と。そりゃ「`」閉じてないしエラー出るわ。
でもcronはなんで%を改行文字に置き換えちゃうんだろう?と思ったんだけど、 例えばこういう使いどころを想定してるのかな・・・?
* * * * * mail -s "test mail" 自分のメールアドレス%WE%LOVE%%CAT!!!%
これでメールを送ると、こんな感じでメールが届きます。 改行として使えるから便利・・・・?
To: 自分のメールアドレス Subject: test mail (中略) From: root <root@infra.xyz> WE LOVE CAT!!!
まあそもそもを言うとログに年月日つけるのが筋が悪いのかも、と思います。
1日1ファイルずつファイルが増えていくし、古いものが消されるわけでもないからディスクひっ迫するし、 1日ごとにファイルを分けたいのであれば、日付なしのファイル名で出してlogrotatedにローテート任せるのが正しい気がする。