「ターミナルから直接実行すると動くのに、crontabに登録するとエラーになる…」
「croncron [クーロン / クロン]Unix系システムにおいて、設定したスケジュールで自動的にコマンドを実行するデーモンのログを見たら command not found になっていた…」
LinuxLinux [リナックス / ライナックス]オープンソースのOSカーネルなどで自動処理を設定する際、このようなエラーに直面したことはありませんか? その原因の一つとして特に多いのが、cronの実行環境では、ログイン時とは異なる環境変数(特にPATH)が設定されていることです。
本記事では、crontabで環境変数が反映されない理由と、それを解決するための3つの具体的な方法を分かりやすく解説します。
記事のポイント
- 原因: cronはログイン時とは異なる限定された環境で実行されるため、
.bashrcなどの環境変数が自動的に引き継がれるとは限りません。- 対策1(推奨): crontabファイルの冒頭で
PATHなどの環境変数を直接定義する。- 対策2: スクリプト内のコマンドやファイル指定をすべて「絶対パス(フルパス)」で記述する。
- 対策3: シェルスクリプト内で
sourceコマンドを使い、専用の環境設定ファイルを読み込む。
なぜcrontabだと環境変数が反映されないのか?
解決策を見る前に、「なぜエラーになるのか」という原因を知っておくことが重要です。
1. cronは「非対話型・非ログインシェル」で実行される
私たちが普段SSHSSH [エスエスエイチ]Secure Shell。暗号化されたリモート接続プロトコルなどでサーバーにログインして作業する環境(ログインシェル)では、ログイン時に自動で .bash_profile や .bashrc、.zshrc といった設定ファイルが読み込まれ、環境変数が構築されます。
しかしcronでは、通常のSSHログイン時とは異なる環境でコマンドが実行されます。そのため、ログインシェルで読み込まれる .bash_profile や、対話型Bashで読み込まれる .bashrc などの設定が、cron実行時に自動的に読み込まれるとは限りません。
また、cronのデフォルトシェルは多くの環境で /bin/sh となっています。そのため、bash特有の機能(配列や [[ ]] による条件判定など)を使ったスクリプトやコマンドをcrontabにそのまま記述すると、予期せぬエラーになることがある点にも注意が必要です。
2. cronのPATHはログイン時と異なる場合がある
cron実行時のデフォルトの PATH は、ログインシェルで使用している PATH とは異なる場合があります(具体的な値はLinuxディストリビューションやcronの実装によって異なります)。
cronではPATHがログインシェルのPATHと異なる場合があり、/usr/local/bin やユーザーのホームディレクトリ配下などが含まれていない場合があります。そのため、Node.jsやPythonPython [パイソン]汎用プログラミング言語のコマンド、/opt などにインストールされたプログラムを呼び出そうとしても、「どこにあるか分からない(command not found)」となってしまうのです。
【解決策】crontabで環境変数を設定する3つの方法
この問題を解決するには、以下の3つのアプローチがあります。状況に合わせて最適なものを選んでください。
方法1:crontabファイル内で直接定義する(一番おすすめ)
最もシンプルで確実なのが、crontab -e で編集するファイルの一番上に環境変数を直接書いてしまう方法です。
この方法なら、そのcrontab内に書かれたすべてのジョブに設定が適用されます。
記述例:
# 環境変数を先頭で定義SHELL=/bin/bashPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin# 必要な場合のみ設定# LANG=ja_JP.UTF-8
# 以下、スケジュールとジョブを記述0 * * * * my_script.shメリット:
- パスを一度定義するだけで済むため、各ジョブの記述がスッキリする。
- サーバー移行時などでも、cronの設定を見るだけで環境が把握しやすい。
⚠️ 注意:crontab内では「コマンド置換」や「変数展開」が使えない
crontabの環境変数定義行で PATH=/usr/local/bin:$PATH のように既存の変数を展開したり、BAR=$(date) のようにコマンド置換($() やバッククォート)を使用することはできません。記述した文字列がそのまま代入されてしまいます。
動的に値を設定したい場合は、各ジョブの実行行の先頭で定義する(例:* * * * * BAR=$(date) /path/to/script.sh)か、シェルスクリプト側で行う必要があります。
方法2:絶対パス(フルパス)で指定する
環境変数(PATH)に依存せず、コマンドの場所を完全に指定してしまう方法です。単発のジョブや、スクリプト内の一部のコマンドだけ動けば良い場合に有効です。
記述例(crontab側):
# pythonではなく絶対パスで指定0 * * * * /usr/bin/python3 /home/user/scripts/app.py記述例(シェルスクリプト側):
#!/bin/bash# スクリプト内でも絶対パスを使う/usr/local/bin/node /home/user/app/index.jsパスが分からない場合は、ターミナルで command -v node や command -v python3 と入力して確認しましょう。(※which コマンドの代わりにPOSIX準拠の command -v を推奨します)
メリットと注意点:
- PATHへの依存を減らせるため、特にコマンドの場所を明確にしたい場合に有効です。
- 注意:ただし、環境変数(
HOMEやLANGなど)やカレントディレクトリなどへの依存までなくなるわけではない点には留意してください。
方法3:スクリプト内で専用の設定ファイルを読み込む
実行したいシェルスクリプトの中で、source コマンド(または . コマンド)を使って必要な環境変数を読み込んでから処理を実行する方法です。
記述例(crontab側):
# .cron_envを読み込んでからスクリプトを実行0 * * * * . $HOME/.cron_env; /home/user/scripts/my_task.sh記述例(シェルスクリプト側):
#!/bin/bash# スクリプトの先頭で読み込むsource ~/.cron_env
node /home/user/app/index.js⚠️ 注意1:/bin/sh では source コマンドが使えない
crontab側から直接設定ファイルを読み込む場合、cronのデフォルトシェル(/bin/sh)では source コマンドがサポートされておらず、実行時にエラーになる可能性があります。
これを防ぐには、crontabの先頭に SHELL=/bin/bash を明記してBashで実行させるか、上記の例のように sh でも動作するPOSIX準拠の .(ドット)コマンド を使用してください。
⚠️ 注意2:.bashrc を読み込む場合のリスク
技術的には source ~/.bashrc とすることも可能ですが、.bashrc には対話型シェル用の設定(プロンプトやエイリアスなど)が多く含まれているため、cronから丸ごと読み込むことはあまりおすすめできません。
代わりに、cron用に専用の設定ファイル(例: ~/.cron_env)を作成し、そこにPATHなどの必要な環境変数だけを書いて読み込ませるのが安全です。
⚠️ 補足:crontab特有の記号の挙動(%など)
環境変数とは少し異なりますが、crontabに直接コマンドを記述する際にハマりやすい落とし穴があります。
それは、crontabのコマンドライン上では %(パーセント)記号が改行として扱われる という特殊な仕様です。
# 日付をつけてログ出力しようとすると、% が改行と見なされてエラーになる* * * * * my_script.sh > /tmp/log_$(date +%Y%m%d).txtこれを回避するには、\% のようにバックスラッシュでエスケープするか、複雑なコマンドや処理はシェルスクリプト側に記述し、それをcronから呼び出すようにしましょう。
💡 小技:cronの環境変数を実際に確認してみる
「今、自分のcronがどんな環境変数で動いているのか?」を知りたい場合は、以下のジョブを一時的に設定してみてください。
* * * * * env > /tmp/cron_env.txt数分待ってから cat /tmp/cron_env.txt を実行すると、そのcronジョブから見える環境変数(PATHやSHELLなど)の一覧が出力されます。ログイン時の env の結果と比較してみると、違いがよく分かるはずです。
※確認が終わったら、毎分実行されてしまうのを防ぐため、必ず crontab -e からこの行を削除しておきましょう。
まとめ:トラブルを未然に防ぐチェックリスト
crontabでジョブを設定する際は、以下のチェックリストを活用して「コマンドが見つからない」エラーを防ぎましょう。
- 前提の理解:cronはログインシェルとは異なる、限定された環境で実行されることを意識しているか?
- PATHの設定:crontabの冒頭で必要なPATHを宣言しているか?
- 絶対パスの利用:コマンド(python, node, curlなど)や対象ファイルはフルパスで書いているか?
- ログの出力:エラー原因を後から追えるよう、標準出力・標準エラー出力をログに書き出しているか?(例:
>> /path/to/cron.log 2>&1)
環境変数の仕組みさえ理解してしまえば、cronでの自動化は怖くありません。ぜひこの記事を参考に、安定したジョブ運用を実現してください。
以上で本記事の解説を終わります。
よいITライフを!
人気記事
- 1
- 2
- 3
- 4
- 5
Rocky Linux対応。実際にWebサーバーを公開するまでのプロセスを体験できる、最も確実で実践的なガイドブックです。