7

I have tried the following and find it to work. This is done with a non-privileged user. First find out where your perl command is:

# which perl

Then check the value of PERL5LIB:

# echo $PERL5LIB

Then, at the crontab file of the user, do something like:

MAILTO=<my email address for the jobs output>
HOME=/home/myhome
PERL5LIB=/home/myhome/perl5/lib/perl5

0 2 * * * $HOME/<rest of path to perl>/perl $HOME/<path to my perl script> arg1 ...

This will run a job at 2am and seems to find all Perl libs correctly. My question is: is this complete and portable? Is there a better way?

I have seen a number of bash and perl scripts out there that are supposed to prepare the environment for the execution of a Perl script, but this seems to suffice. Any advice will be welcome!

EDIT: From the comments to the question, it seems that I am using a "bad" mixture of Perlbrew and local::lib. The way to make sure libraries get installed inside a particular Perlbrew version is answered here: How do I install CPAN modules while using perlbrew?. Both cpan and cpanm will install under PERL5LIB when you are using local::lib unless you explicitly tell them to do otherwise. Also cpanm seems to be better suited to working along with Perlbrew.

Javier Elices
  • 2,066
  • 1
  • 16
  • 25
  • 3
    Take a look and read about the [Ubic](https://metacpan.org/release/Ubic). It is sure an overkill for your use-case, but you could get some ideas... – clt60 Nov 23 '17 at 15:09
  • 1
    You should be able to run something like `bash 'perlbrew use perl-5.28.0; perl $HOME/' from cron. That will pick a specific Perl for that sub-shell and set everything automatically. – simbabque Nov 23 '17 at 15:33
  • 2
    @simbabque Except that `perlbrew use` seems to exec into a new shell, so you'd need to pipe commands into it: `perlbrew use perl-5.26 <<<'perl ./some-script.pl'` (Bash syntax). `perlbrew exec --with perl-5.26 'perl ./some-script.pl'` would be equivalent, but prints an annoying header before the output. – amon Nov 23 '17 at 15:58
  • @jm666, thank you for the suggestion. Ubic seems like overkill as you say, but it does look interesting for services management in general. – Javier Elices Nov 23 '17 at 17:24
  • 2
    It doesn't make much sense to use local::lib with `perlbrew`, so you shouldn't be setting `PERL5LIB`. – ikegami Nov 23 '17 at 17:28
  • @ikegami, how then? It is what makes my simplistic way of running Perl scripts work. If I don´t set `PERL5LIB` I only get some of the `@INC` directories in the running Perl script and then `use` will not consider certain libraries ending up in a compile-time error. – Javier Elices Nov 23 '17 at 17:33
  • Re "*I only get some of the @INC directories in the running Perl script*", Right, and that's where the modules you should be installed. It makes no sense to install them elsewhere. – ikegami Nov 23 '17 at 18:08
  • @ikegami, I am using `cpanm ` to install modules and they end up in the `PERL5LIB` directory. `cpan` seems to do the same. Are you suggesting that they should be installed for each specific Perl version? I am using Perlbrew to have a local Perl (and libraries) for a user, not to use more than a single Perl version, so I was not paying attention to the place libraries were going. – Javier Elices Nov 23 '17 at 19:03
  • Re "*and they end up in the PERL5LIB directory.*", That's because you are using install::lib and you shouldn't. It's likely to cause problems, and there's no reason to use it. – ikegami Nov 23 '17 at 19:05
  • @ikegami, ok, I think that now I see what you mean. `local::lib` is meant to have libraries local to a user but with the system-wide Perl. Perlbrew is meant to have a whole Perl + libraries environment local to a user. Am I right? But do you see a problem if I stick to a single Perlbrew interpreter? It would take some effort to go back... – Javier Elices Nov 23 '17 at 19:24
  • @amon --- to surprise that annoying message, you can tell perlbrew to be `--quiet`. I use it in some off my `~/.bash_prfofile` aliases that require some perl modules. But I do not want to clutter my installed Perls like `alias minidoc='perlbrew exec --quiet --with perl-5.26.1@minicpan mcpandoc -MPod::Text::Color::Delight'` – vanHoesel Nov 23 '17 at 19:38
  • 1
    @amon, Re "*Except that perlbrew use seems to exec into a new shell,*", Not if you have perlbrew properly setup. There's a file that needs to be `source`d at shell startup. You're describing the backup behaviour when that isn't done. – ikegami Nov 23 '17 at 19:58
  • Re "*But do you see a problem if I stick to a single Perlbrew interpreter?*", I don't see how you can do that. Lots of things use the system `perl`, and you'll need to upgrade eventually. – ikegami Nov 23 '17 at 19:59
  • @ikegami, I don´t see what you mean. I have a non-privileged user that uses `local::lib` so its `PERL5LIB` variable points to a directory of this user and then Perlbrew to have a different Perl version than the system´s one. The libraries get installed under the `PERL5LIB` directory which is local to the user. The `crontab` file I refer to is also the user´s. – Javier Elices Nov 23 '17 at 20:21
  • @ikegami, sorry, I have read my question and see I don´t mention the user anywhere. I have edited it to make this clear. – Javier Elices Nov 23 '17 at 20:26
  • Re "*I don´t see what you mean.*", You said you could guarantee that the only `perl` a user would only use was a specific one installed using `perlbrew`. I said I don't believe you can guarantee that. Lots of stuff use the system `perl`. – ikegami Nov 23 '17 at 20:57
  • Re "*I have a non-privileged user that uses local::lib [with a `perl` installed in their home dir]*", I know that. They shouldn't be using local::lib. local::lib is a hack whose need was eliminated by the installation of a `perl` to which they have full access. – ikegami Nov 23 '17 at 21:03
  • @ikegami Re new shell: oh. oooh! That explains a lot. Thank you very very much for your pointer. – amon Nov 23 '17 at 21:46
  • Re "*Both cpan and cpanm will install under PERL5LIB*", That's not true. They don't use PERL5LIB. – ikegami Nov 24 '17 at 03:10
  • It should be both `cpan` and `cpanm` install under `PERL5LIB` by default when you have `local::lib`. Fixed in the question. Thanks. – Javier Elices Nov 24 '17 at 12:17

2 Answers2

2

The shebang (#!) line of the script should point to the (perlbrew-installed) perl it is meant to run under. (This should be done as part of installing the script.) That's all you need.

0 2 * * * /path/to/script arg1 ...
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • ++ this is exactly why Gugod introduced the `alias` feature after removing the "current" symlink. See: https://github.com/gugod/App-perlbrew/issues/142 – G. Cito Nov 23 '17 at 21:10
  • I assume that you could use a *regular* shebang and invoke the right Perl interpreter from *crontab* as `0 2 * * * /path/to/perl /path/to/script arg1 ...`. This would let you move the script around without hardcoding the Perl interpreter that it needs. Am I right? – Javier Elices Nov 23 '17 at 21:24
  • Yes, you could hardcode it in the cron job and everywhere else you use it instead, but that's bad!!! It's supposed to be hardcoded in the script when you install it. That way, the script is only used with the `perl` under which it was tested and installed. The standard Perl installers even rewrite `#!/usr/bin/perl` into the proper path automatically for you. It saves you from hardcoding it in a million places (e.g. the cron files), or from using an installation that's not wasn't setup for it. I stand by my answer. – ikegami Nov 23 '17 at 21:35
  • @ikegami, thanks a lot for the explanation! It makes a lot of sense. My doubts come from the fact that I tend to code in Perl in a version-independent way. Probably because I tend to use the system´s Perl interpreter in cPanel managed machines, which change it over time.. – Javier Elices Nov 23 '17 at 21:47
  • I'm not sure why you think that's different. Don't your scripts that use the system `perl` have `#!/usr/bin/perl` as their first line? – ikegami Nov 23 '17 at 21:49
  • Well, you may not like it :-), but it is possible to use `/usr/bin/env perl` to make sure the system finds a Perl interpreter for you in your `PATH`. You cannot guarantee which version but I guess `use ` was created for that. – Javier Elices Nov 23 '17 at 22:03
  • It's not a question of liking or not. That's a horrible idea. It causes the script to break when you use `perlbrew` since it changes your path. – ikegami Nov 23 '17 at 22:06
2

If you already have multiple perl installations managed with perlbrew the easiest approach is to just use perlbrew exec to run your script. The -q and --with options allow you to silence superfluous output and select the specific version of perl to run the script/job. Try something like:

  • perlbrew exec perl -E 'say "Hello from $]\n"' (this will show errors from older versions (< 5.10) of perl that don't have the -E switch enabled by default).
  • perlbrew exec -q --with 5.26.1 perl -E 'say "Hello from $]\n"' (this will run the command and suppress informational output).
  • perlbrew exec -q --with 5.26.1 perl ~/script_from_heaven.pl (runs the script with the perl version requested).
  • perlbrew exec -q --with 5.26.1 ~/script_from_heaven.pl (runs the script with the perl version requested or hard-coded in the script's shebang line).

I tend to explicitly set PERL5LIB and use local::lib only when I need them or for certain users or environments where I exclusively install all CPAN modules in $HOME/perl5/lib/perl5 (a full application deployment, say). Otherwise I find running perl from perlbrew pretty convenient.


A couple of things I've found helpful: setting an alias for perlbrew environments that you want to keep stable for a particular use can be a useful way to manage multiple perls:

 ~/$ perlbrew alias create perl-5.24.0 stable-cronperl
 ~/$ perlbrew list
 perl-5.8.9
 perl-5.10.1
 perl-5.24.0
 cperl-cperl-5.26.1
 stable-cronperl (5.24.0)
 perl-5.26.1

NB: however the alias is only useful/useable as a stable #! shebang anchor for use at the top of your scripts if you want to make them executable:

#!/home/cronic/perl5/perlbrew/perls/stable-cronperl/bin/perl

You can't refer to an alias using --with for example:

perlbrew exec --with stable-cronperl ~/smart_comments.pl

Reporting this as either a documentation issue or a bug is on my to do list.

G. Cito
  • 6,210
  • 3
  • 29
  • 42
  • 1
    There is also Tokuhirom's [`plenv`](https://github.com/tokuhirom/plenv) ;-) Miyagawa has been adding the "missing" `perlbrew` commands to `plenv`: https://github.com/miyagawa/plenv-contrib – G. Cito Nov 23 '17 at 21:14
  • I find your answer more complete, but ikegami´s more correct. So I will mark his as correct but give you my upvote. – Javier Elices Nov 24 '17 at 09:42