導入
「手で打つと動くのに、cron に登録すると動かない」。cron の相談の9割はこれです。原因はほぼ決まっていて、環境が違うの一言に尽きます。先に知っておけば、丸一日を溶かさずに済みます。
説明
cron がスクリプトを実行するときの環境は、あなたがログインして打つときとは別物です。
| 項目 | ログインして打つとき | cron が実行するとき |
|---|---|---|
PATH | /usr/local/bin などフルセット | 最小限(/usr/bin:/bin 程度) |
| カレントディレクトリ | いまいる場所 | ホームディレクトリ |
| 環境変数 | .bashrc などが読み込まれた状態 | ほとんど無い |
| 画面 | ある(出力が見える) | 無い(出力は消えるかメールに) |
この違いが、そのまま3つの落とし穴になります。
#!/bin/bash
# 落とし穴1: 相対パスは「ホームからの相対」になる
# 悪い例: cat logs/app.log ← cron ではホーム基準になり、意図とずれる
# 良い例: 絶対パスで書く
cat /home/user/logs/app.log | wc -l
# 落とし穴2: コマンドが見つからない(PATH が短い)
# 良い例: スクリプトの冒頭で PATH を自分で設定する
PATH=/usr/local/bin:/usr/bin:/bin
echo "PATH: $PATH"
# 落とし穴3: 出力が消える
# 良い例: ログファイルに残す(第3章のリダイレクト)
echo "処理しました" >> /home/user/cron.log 2>&1
対策は3つとも単純です。
- パスは絶対パスで書く(
/home/user/scripts/backup.sh、cd /home/user/filesを冒頭に置くのも可) - PATH を自分で設定する(スクリプトの冒頭、または crontab の先頭行に
PATH=…) - 出力をログに残す(
>> /var/log/mybatch.log 2>&1)
crontab の書き方としては、こうなります。
PATH=/usr/local/bin:/usr/bin:/bin
0 3 * * * /home/user/scripts/backup.sh >> /home/user/backup.log 2>&1
flowchart TD
A["手元では動く"] --> B{"cron で動かない"}
B --> C["相対パス?<br/>→ 絶対パスにする"]
B --> D["コマンドが見つからない?<br/>→ PATH を設定"]
B --> E["何も起きない?<br/>→ 出力をログに残して確認"]
もう1つ、
%は crontab では特別な意味(改行)を持ちます。date +%Y-%m-%dをそのまま crontab に書くと壊れるので、\%とエスケープするか、そもそもスクリプトの中に書いてしまうのが安全です。cron には「スクリプトを呼ぶだけ」を登録する、と決めておくと、この手の罠をまとめて避けられます。
やってみよう
スクリプトを実行して、絶対パスでの読み込みと PATH の設定を確認しましょう。次に端末で cat cron.log として、追記されたログを見てください。そのうえで、上のスクリプトを crontab に登録して cronsim で動かすと——cron から実行されても、絶対パスなら正しく動くことが確かめられます。
演習
/home/user/logs/app.log を絶対パスで読んで行数を表示してください(8行です)。
ヒント1を見る
相対パスの logs/app.log を /home/user/logs/app.log に変えます。
ヒント2を見る
cat /home/user/logs/app.log | wc -l