手で実行できる処理が、cronだと動かない場合
コンソールから手でたたいて実行できる処理を、cronに入れて定時に自動で実行しようとしても、正しく実行しない場合があります。大抵は、パスを認識していないことが多いです。
cronでエラーを出力する
crontabに引数を与えて、エラーをファイルに出力してみます。
20 12 * * * /work/prg/test.csh > /work/prg/test_1.log 2>&1
出力結果を見ると、
Can't locate Net/SMTPS.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5/usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at /work/prg/test.pl line 39. BEGIN failed--compilation aborted at /work/prg/test.pl line 39.
となりました。やはり、ライブラリが見つかりませんと怒られてしまっています。ファイルやプログラムのパスは、
$conv_prg = '/usr/bin/'; ${conv_prg}convert
のように、あえてフルパスを設定し、実行すれば確実に動きます。でも、モジュールは
use Net::SMTPS;
と、パスを指定することができません。perl本体で、モジュールのパスを認識しているようです。
モジュールの保存場所の確認
では、どこにモジュールがあると認識しているのか、知りたいですよね。
使うのは、perldocコマンドです。
#perldoc -l Net::SMTPS /root/perl5/lib/perl5/Net/SMTPS.pm
やはり、/rootに保存していました。ここにあると、cronで実行すると認識しないんですよね。他のモジュールはどこになるのかみてみますと、
# perldoc -l Net::SMTP /usr/share/perl5/Net/SMTP.pm
と、/usrなので、cronで認識します。SMTPはもともと入っていたモジュール、SMTPSはCPANからインストールしたモジュールです。そこで、CPAN実行時のインストール先を見てみました。
Installing /root/perl5/lib/perl5/Net/SMTPS.pm Installing /root/perl5/man/man3/Net::SMTPS.3pm
なんと、rootにインストールしてしまっていて、/usrなんちゃらに入っていませんでした。それはエラーが起きますよね。
どうやら、CPANの設定に何かがありそうです。
CPANの設定を変更する
ネットで調べてみた所、まとめている方がいらっしぃます。参考にさせて頂きました。
CPANの設定は、cpan[1]> o conf で見ることができます。
makepl_arg [INSTALLDIRS=site] mbuildpl_arg [--installdirs site]
となっているのを確認します。[]が空欄でしたら、 vim ~/.cpan/CPAN/MyConfig.pm で記述します。
問題がなさそうでしたら、環境変数を見て見ます。
#printenv | grep perl PERL5LIB=/root/perl5/lib/perl5:/root/perl5/lib/perl5: PERL_MB_OPT=--install_base /root/perl5 PATH=/root/perl5/bin:/root/.pyenv/plugins/pyenv-virtualenv/shims:/root/.pyenv/shims:/root/.pyenv/bin:/usr/lib64/qt-3.3/bin:/root/perl5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin PWD=/root/perl5/lib/perl5/Net PERL_LOCAL_LIB_ROOT=:/root/perl5:/root/perl5 PERL_MM_OPT=INSTALL_BASE=/root/perl5
ライブラリに/rootと指定されています。指定を解除したいですね。
環境変数にライブラリを指定しているファイルがあり、 ~/.bashrc になるとのことです。
ファイルを開くと、
export PERL_LOCAL_LIB_ROOT="$PERL_LOCAL_LIB_ROOT:/root/perl5"; export PERL_MB_OPT="--install_base /root/perl5"; export PERL_MM_OPT="INSTALL_BASE=/root/perl5"; export PERL5LIB="/root/perl5/lib/perl5:$PERL5LIB"; export PATH="/root/perl5/bin:$PATH";
これらをコメントアウトします。これで、次からのインストールは大丈夫になります。
すでにインストールしたモジュールは?
ただ、すでにインストールしたモジュールはどうしたらいいのでしょうか。
それは、@INCのパス( /usr/local/lib64/perl5とか )に、自分でモジュールを置くことがいいかなと。
でも、コピーはだめです。移動です!コピーだと、
# perldoc -l Net::SMTPS /root/perl5/lib/perl5/Net/SMTPS.pm
と、何ら変わりません!コピーをしていても、元ファイルがあるとそちらの方が優先されるんですね。消すと何かあるといけないとそのままにしがちですが、ここは思い切りが大事です。移動をしましたら、
# perldoc -l Net::SMTPS /usr/share/perl5/Net/SMTPS.pm
となりました。これで安心です。
それでもできない場合が…
crontabに入れて実行してみました。
ところが、エラーは吐き出さないのに、なぜか上手くいきません。もしやと思いますが、他のモジュールが影響していそうです。
モジュールのソースから、他のモジュールも確認
そこで、モジュールのソースを開いてみます。 コメント行に、
# Authen::SASL, MIME::Base64 should be installed.
と書いてありました。これは、気がつかないです。そのモジュールのパスも見て見ますと、
# perldoc -l Authen::SASL /root/perl5/lib/perl5/Authen/SASL.pod
やっぱり…。一緒にインストールしたんでしょうかね。こちらも移動しておきました。そうしたら、やっとcronでも実行できました。
まとめ
プログラムを書く際は、相対パスではなくフルパスを設定するようにしています。ただ、モジュールは使えるものと思って、気にしていませんでした。モジュールがどこにあるか、知っておくのが大切です。CPANとかで便利にインストールができるのですが、こちらの設定も見ておく必要がありますね。
ディスカッション
コメント一覧
まだ、コメントがありません