英文:
how to make cpan modules available in cron
问题
我的Perl脚本,jaw20230325printcalendartodisk.pl,依赖于File::Rsync
模块。
我必须运行cpan File::Rsync
来在我的计算机上获取这个模块,我的计算机是MacBook Pro,运行macOS Ventura 13.4。
脚本jaw20230325printcalendartodisk.pl并不直接使用File::Rsync
,而是使用了我编写的Perl模块QuemQuaeritis.pm,而这个模块使用了File::Rsync
。
在命令行上,jaw20230325printcalendartodisk.pl脚本可以正常运行。但是我想要在cron下运行它:
> crontab -l
00 16 * * * $HOME/u/kh/pm/jaw20230325printcalendartodisk.pl
但这导致以下错误:
无法在@INC中找到File/Rsync.pm(您可能需要安装File::Rsync模块)(@INC包含:/Users/kpr/u/kh/pm
/usr/local/opt/perl/lib/perl5/site_perl/5.36/darwin-thread-multi-2level /usr/local/opt/perl/lib/perl5/site_perl/5.36
/usr/local/opt/perl/lib/perl5/5.36/darwin-thread-multi-2level /usr/local/opt/perl/lib/perl5/5.36 /usr/local/lib/perl5/site_perl/5.36)位于
/Users/kpr/u/kh/pm/QuemQuaeritis.pm第2061行。
BEGIN失败-在/Users/kpr/u/kh/pm/QuemQuaeritis.pm第2061行中中止编译。
在/Users/kpr/u/kh/pm/jaw20230325printcalendartodisk.pl第39行需要Compilation。
BEGIN失败-在/Users/kpr/u/kh/pm/jaw20230325printcalendartodisk.pl第39行中中止编译。
因此,看起来cpan使File::Rsync
在我的shell中可用,但在cron下不可用。
jaw20230325printcalendartodisk.pl在cron下曾经正常运行,但是在这台机器上的某个时候,我运行了brew install python
。
然后它安装了一个名为python3的东西。只有在安装之后,我的代码才停止在cron下运行。
根据我运行cpan时打印的警告,以下已经是我的.bash_profile中的最后一行四个月了:
eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib=$HOME/perl5)"
这意味着我不必在macOS升级时每次重新安装模块。
那么,如何使我的cpan模块在cron下可用,也就是当我不在shell中运行时?
或者,如何防止安装python3干扰访问我的cpan安装的Perl模块?
附加信息:
> perldoc -l File::Rsync
/Users/kpr/perl5/lib/perl5/File/Rsync.pm
我认为这与上面的.bash_profile的最后一行是一致的。
我认为这行意味着当我在cpan下安装一个模块时,它会放在我的HOME目录下,而不是放在Perl的其他位置。
英文:
My perl script, jaw20230325printcalendartodisk.pl,
depends on File::Rsync
.
I had to do cpan File::Rsync
to get this module on my computer,
which is macbook pro, macos Ventura 13.4.
The script
jaw20230325printcalendartodisk.pl
does not directly use File::Rsync
but
rather uses a perl module I wrote,
QuemQuaeritis.pm,
which uses File::Rsync
.
jaw20230325printcalendartodisk.pl
runs fine on the command line.
But I want to run it under cron:
> crontab -l
00 16 * * * $HOME/u/kh/pm/jaw20230325printcalendartodisk.pl
and this leads to the following error:
Can't locate File/Rsync.pm in @INC (you may need to install the File::Rsync module) (@INC contains: /Users/kpr/u/kh/pm
/usr/local/opt/perl/lib/perl5/site_perl/5.36/darwin-thread-multi-2level /usr/local/opt/perl/lib/perl5/site_perl/5.36
/usr/local/opt/perl/lib/perl5/5.36/darwin-thread-multi-2level /usr/local/opt/perl/lib/perl5/5.36 /usr/local/lib/perl5/site_perl/5.36) at
/Users/kpr/u/kh/pm/QuemQuaeritis.pm line 2061.
BEGIN failed--compilation aborted at /Users/kpr/u/kh/pm/QuemQuaeritis.pm line 2061.
Compilation failed in require at /Users/kpr/u/kh/pm/jaw20230325printcalendartodisk.pl line 39.
BEGIN failed--compilation aborted at /Users/kpr/u/kh/pm/jaw20230325printcalendartodisk.pl line 39.
So it appears that cpan made File::Rsync
available in my shell, but not under cron.
jaw20230325printcalendartodisk.pl used to run fine under cron, but
this week
I did brew install python
on this machine.
It then installed something called python3.
Only
after that installation did my code stop running under cron.
Based on warnings that were printed when I ran cpan,
the following has been the final line in my .bash_profile for four months:
eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib=$HOME/perl5)"
This is supposed to mean that I do not have to reinstall modules each time the macos is upgraded.
Thus, how do I make my cpan modules available under cron, i.e., when I am not running in the shell?
Or alternatively, how can I prevent an installation of
python3 from interfering with the accessibility of my
cpan-installed perl modules?
Additional information:
> perldoc -l File::Rsync
/Users/kpr/perl5/lib/perl5/File/Rsync.pm
I believe this is consistent with the final line of .bash_profile above.
I think that line means that when I install a module under cpan,
it is put under my HOME directory, not where the rest of perl is installed.
答案1
得分: 2
将以下内容添加到您的crontab中:
PERL5LIB=/Users/kpr/perl5/lib/perl5
或者可能是
PERL5LIB=$HOME/perl5/lib/perl5
这将产生与local::lib相同的效果。(嗯,它的相关部分。您可以运行perl -I$HOME/perl5/lib/perl5 -Mlocal::lib=$HOME/perl5
来查看它设置的所有变量。)
英文:
Add the following to your crontab:
PERL5LIB=/Users/kpr/perl5/lib/perl5
Or possibly
PERL5LIB=$HOME/perl5/lib/perl5
This will have the same effect local::lib. (Well, the relevant part of it. You can run perl -I$HOME/perl5/lib/perl5 -Mlocal::lib=$HOME/perl5
to see all the vars it sets.)
答案2
得分: 1
作业在crontab(5)
中运行时,处于受限环境中,程序不能简单地依赖于用户的 shell 环境和配置。解决这个问题的一种方法是在程序中设置一切。
当解释器需要加载一个模块时,它会在全局的@INC数组中给定的路径中搜索它。在这种情况下,它将查找一个名为File
的目录,然后在其中查找一个名为Rsync.pm
的文件。还请参阅require和perlmod。
因此,如果这个模块安装在@INC
中尚不存在的位置,那么需要将包含File/Rsync.pm
的路径添加到@INC
中。最好的方法是使用lib pragma。
问题中给出了模块的位置为/Users/kpr/perl5/lib/perl5/File/Rsync.pm
,所以可以这样做:
use lib '/Users/kpr/perl5/lib/perl5';
use File::Rsync;
现在这应该能够通过 cron 运行。
一条评论澄清了/Users/kpr
是主目录,尽管它可能看起来是如此。在这种情况下,更好的做法是使用$ENV{HOME}:
use lib "$ENV{HOME}/perl5/lib/perl5";
更具体地说,评论指出这在其他机器上是不同的(因此在这些机器上,该模块安装在不同的目录中),这也使得它成为可移植性问题的一个很好的例子。
英文:
Jobs run out of crontab(5)
are in a restricted environment and a program cannot simply rely on the user's shell environment and configuration. One way out of that is to set up everything in the program.
When the interpreter needs to load a module it searches paths given in the global @INC array for it. In this case it'll look for a directory File
and then for a file Rsync.pm
in it. Also see require, and perlmod.
So if this module is installed in a location which isn't already in @INC
then one needs to add to @INC
that path, in which File/Rsync.pm
is. The best way to do that is via the lib pragma.
The question gives the module's location as /Users/kpr/perl5/lib/perl5/File/Rsync.pm
so
use lib '/Users/kpr/perl5/lib/perl5';
use File::Rsync;
Now this should be able to run via cron.
A comment clarifies that /Users/kpr
is the home directory, as it may seem. Then it is indeed better to use $ENV{HOME} instead,
use lib "$ENV{HOME}/perl5/lib/perl5";
More specifically, the comment states that this is different on other machines (so on those machines the module is installed in different directories), and then this also makes it a good example of portability issues.
答案3
得分: 0
@ikegami的回答几乎肯定适用于您,但另一种(更通用的)解决方案是通过您的shell使cron运行一个命令。这样可以确保您的shell为您提供的所有通常环境都将可用。
在crontab中类似这样的内容:
00 16 * * * /usr/bin/bash -c "$HOME/u/kh/pm/jaw20230325printcalendartodisk.pl"
这可能效率稍低一些,但对于每天运行一次的脚本,运行时多用一点微秒可能不是一个问题。
英文:
@ikegami's answer will almost certainly work for you, but another (more general) solution is to get cron to run a command via your shell. This ensures that all the usual environment your shell provides for you will be available.
Something like this in crontab:
00 16 * * * /usr/bin/bash -c "$HOME/u/kh/pm/jaw20230325printcalendartodisk.pl"
This is slightly less efficient, but for a script run once per day, a few extra microseconds of runtime is likely not a concern.
答案4
得分: -1
"Recall that QuemQuaeritis.pm holds the subs for my module, including the sub that was trying to run when I got the error.
The script that ran under my shell but not in crontab invoked a sub that contained use File::Rsync;
. It was at that line that the error was thrown under cron/crontab.
Thanks to comments, I put the following into the early lines of QuemQuaeritis.pm:
use lib $ENV{HOME} . '/perl5/lib/perl5/';
and then my script ran fine under cron."
英文:
Recall that
QuemQuaeritis.pm holds the subs for my module,
including the sub that was trying to run when I got the error.
The script that ran under my shell but not in crontab invoked a sub that contained
use File::Rsync;
.
It was at that line that the error was thrown under cron/crontab.
Thanks to comments, I put the following into the early lines of QuemQuaeritis.pm :
use lib $ENV{HOME} . '/perl5/lib/perl5/';
and then my script ran fine under cron.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论