mochikoAsTechのdig日記

当方好きなコマンドはdigです!お友達から!!よろしくお願いします!!!

crontabでファイル名に日付が入ったログを吐くときはdateの%をエスケープしないとダメ

たとえば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にローテート任せるのが正しい気がする。