Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Trouble finding modules from cron

by faineant (Beadle)
on Apr 11, 2017 at 16:31 UTC ( #1187661=perlquestion: print w/replies, xml ) Need Help??

faineant has asked for the wisdom of the Perl Monks concerning the following question:

I'm new to Perl. Not even new to Perl; I've inherited a bunch of perl scripts and I need to get them running on a new server.

I have several that I can run when I'm logged in, but when I run them from cron I get the following error:

Can't locate Foo/Bar.pm in @INC (@INC contains: ....

Any assistance would be greatly appreciated

Thanks - F

Replies are listed 'Best First'.
Re: Trouble finding modules from cron
by huck (Prior) on Apr 11, 2017 at 17:03 UTC

    Knowing this will probably happen again i would make a script called /usr/bin/perlcron

    #!/bin/sh perl -I /some/special/libpath:/another/special/libpath "$@"
    and chmod ugo+x it. Then when you enter your command to be run by cron just preface it with /usr/bin/perlcron. ie "/usr/bin/perlcron myscript". This has the advantage that you can also do things like setup a special path when your path is not the path that cron uses. That way you dont need to add any special code to your scripts, it is taken care of in perlcron. And the next time you want to run a perl script by cron you are all set to go,, just use perlcron again to start it

      Nice. I feel silly for how many scripts Iíve edited around this problem when there was such a simple and obvious way around it. Next time I need to update something, Iíll try this approach.

      #!/bin/sh perl -I /some/special/libpath:/another/special/libpath "$@"

      Drop in an exec to get rid of a needless /bin/sh instance:

      #!/bin/sh exec perl -I /some/special/libpath:/another/special/libpath "$@"

      And if you have more than one perl, specify which one you want to start. Also do this if you are not sure what $ENV{'PATH'} may contain.

      #!/bin/sh exec /usr/local/perl-5.42.99/bin/perl -I /some/special/libpath:/anothe +r/special/libpath "$@"

      But then again, cbeckley++ is right, perl can do fine without a shell:

      #!/usr/local/perl-5.42.99/bin/perl use lib '/some/special/libpath','/another/special/libpath'; # rest of the script here, unmodified

      Perl does not even mind if you prefix those two lines to an existing script, the shebang (#!) line of the existing script will be parsed as a comment.

      If you don't want to modify scripts, you can also use a perl script as a wrapper:

      #!/usr/local/perl-5.42.99/bin/perl use lib '/some/special/libpath','/another/special/libpath'; require '/path/to/real/script.pl';

      (untested)

      This simple one assumes that script.pl returns a true value. Alternatively, use do $filename, but that needs more code for error handling:

      #!/usr/local/perl-5.42.99/bin/perl use lib '/some/special/libpath','/another/special/libpath'; unless (defined(do '/path/to/real/script.pl')) { die "Could not parse script: $@" if $@; die "Could not read script: $!"; }

      (untested)

      Generally, if you run a script as root or setuid root, consider adding -T to the shebang line to enable taint mode (see perlsec).

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      I've tried your suggestion and the one provided by cbeckley.

      Both work, but are there reasons for choosing one approach over the other?

      Thanks -F

        In the "-I" approach the biggest consideration comes from module movement. If the modules move from /some/location to /another/location only one place (/usr/bin/perlcron) needs to change and all the programs using those modules are repaired. When using findbin/lib each program itself has to be repaired. At one site i was at we moved boxes 4 times in about 7 years, each move with changes to the names of the file system paths. In that case it wasnt for cron, but to ensure a working production environment. As soon as i fixed the initiator-script all the processes worked under the new locations. I also use this method still on my home boxes, various windoz and linuxen, each with its own customized initiator script to let it run in that environment.

Re: Trouble finding modules from cron
by cbeckley (Curate) on Apr 11, 2017 at 16:41 UTC

    @INC is where perl looks for modules. Perl populates that array from several sources, including the environment variable $PERL5LIB.

    Perhaps you have $PERL5LIB set in your environment? This might be what's going on since it works for you but not for cron.

    If that's the case, you could set the variable in the crontab entry, however, I prefer to do something like this in the calling script:

    use FindBin; use lib "$FindBin::Bin/../path/to/modules";
    This assumes your modules are reliably in the same relative location with respect to your scripts.

    Otherwise you could just use the path directly, although this makes me itch a little:

    use lib "/full/path/to/modules";

    Hope this helps.

    Thanks,
    cbeckley

      This worked!

      use FindBin; use lib "$FindBin::Bin/../path/to/modules";

      Thank you!

Re: Trouble finding modules from cron
by kennethk (Abbot) on Apr 11, 2017 at 16:45 UTC
    The environments are probably different between your log-in and cron. Once you've identified which path is missing from the cron environment (run perl -E'say for @INC' as yourself and as cron, check the gaps for the libraries), you can either modify the scripts using lib (e.g., use lib '/usr/local/lib64/perl5';) or modify cron's environment.

    There's also a possibility here of local pathing, but the solution there is essentially the same. There's also a possibility of a permissions issue (cron doesn't have read privileges for the libraries), which requires some chmoding or group-level access modification.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      Ah, I had assumed (never a good idea) that the cron user and the interactive user were the same.

      Some additional questions for faineant:

      • Are the cron and interactive users the same?
      • Is Foo/Bar.pm part of the scripts you've inherited?
      • If you have access to the old system, is PERL5LIB set?
      • What is the value of @INC on the old system vs the new system?

      Thanks,
      cbeckley

        The cron user is the same as the interactive user.
        Foo/Bar.pm is part of the script tree that I have to port.
        PERL5LIB is set on the old system but I can't figure out where.
        I'm not sure if can share @INC on a public forum

        I can't believe how much help I'm getting and how quickly!

        Thank you all so much!>

        Thanks -F

Re: Trouble finding modules from cron
by kcott (Archbishop) on Apr 12, 2017 at 14:02 UTC

      Thank you!

      Thank you for the links. I followed them, and I think I get it, but I gotta say, I'm a little over my head here. It's daunting how many permutations there are. And I suspect this is just the beginning.

      Thanks -F

Re: Trouble finding modules from cron
by faineant (Beadle) on Apr 12, 2017 at 19:39 UTC

    I just wanted to thank everybody for such great responses! You lot are amazing.

    Both the amount of information and the speed, this was totally unanticipated!

    I confess, I'm a bit overwhelmed, but this is amazing.

    Thank you, everybody!

    Thanks -F

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1187661]
Approved by Paladin
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2023-12-06 17:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What's your preferred 'use VERSION' for new CPAN modules in 2023?











    Results (31 votes). Check out past polls.

    Notices?