【问题标题】:Can't locate in @INC Perl perl file loaded by "require"无法在“require”加载的@INC Perl perl 文件中找到
【发布时间】:2021-08-08 11:27:10
【问题描述】:

我有一个简单的 Perl 脚本,它使用位于另一个文件 common.pl 中的辅助函数:

main.pl

#!/usr/bin/perl

use strict;
use warnings;

use Cwd 'abs_path';

use File::Basename qw( fileparse );
use File::Path qw( make_path );
use File::Spec;


require "common.pl";  # line 15

#...

common.pl

#!/usr/bin/perl

use strict;
use warnings;

sub getTimeLoggerHelper{
  #....
}

1;

本地一切运行良好,但是当我尝试通过 ssh 运行它时出现错误:

Can't locate common.pl in @INC  (@INC contains: 
/Library/Perl/5.18/darwin-thread-multi-2level  /Library/Perl/5.18 
/Network/Library/Perl/5.18/darwin-thread-multi-2level
/Network/Library/Perl/5.18
/Library/Perl/Updates/5.18.2/darwin-thread-multi-2level
/Library/Perl/Updates/5.18.2
/System/Library/Perl/5.18/darwin-thread-multi-2level
/System/Library/Perl/5.18 
/System/Library/Perl/Extras/5.18/darwin-thread-multi-2level
/System/Library/Perl/Extras/5.18 .) at /Users/snaggs/scripts/main.pl line 15.

[编辑 1]

如果我登录到远程计算机并运行相同的脚本,则不会出现错误。

[编辑 2]

我还尝试将common.pl 转换为模块:

common.pm

package Common;

use strict;
use warnings;

sub getTimeLoggerHelper{
  #....
}

1;
__END__

main.pl 我这样称呼它

use Module::Load;
load Common;

同样的问题,本地工作,来自 ssh - 同样的错误:

Can't locate Common.pm in @INC (you may need to install the Common module)

如何解决这个问题?

【问题讨论】:

  • Perl 中没有load。那是语法错误。 common.pl 文件在哪里?
  • @simbabque 在与main.pl 相同的文件夹中
  • @simbabque:loadModule::Load提供,在前一行导入。
  • @borodin 我明白了。我想我还是睡着了。新年快乐! :-)

标签: perl ssh


【解决方案1】:

如果您需要为此使用require,请提供完整路径

require "/full/path/to/common.pl";

这在ssh 上是必需的,即使文件与脚本位于同一目录中,因为在ssh@INC 中的.不是脚本的目录(因为工作目录. 可能是您的$HOME)。在其他情况下也会发生这种情况。

请注意,这样您将导入common.pl 中的所有内容

改用合适的模块有很多好处。然后文件是.pm,按照惯例,文件名大写(和帕斯卡大小写)。

这是一个简单的示例,包含文件 bin/main.pllib/Common.pm

bin/main.pl

use warnings;
use strict;

use FindBin 1.51 qw($RealBin);  # Directory in which the script is
use lib "$RealBin/../lib";      # Where modules are, relative to $RealBin

use Common qw(test_me);

test_me();

设置@INC 的关键部分,在其中查找模块, 使用lib pragma 完成。它在编译时将目录添加到默认@INC 的开头。 FindBin$RealBin 是脚本的目录,链接已解析。我们使用它以便添加的路径是相对于脚本的,而不是硬编码的。当脚本及其库结合在一起时,这有助于源组织。

另一种设置方法是通过environment variable PERL5LIB。与bash

export PERL5LIB=/path/to/libdir

然后,对于Module.pm 中的libdir,您只需说出use Module 即可找到它。这对于位于特定位置的模块很有用,供各种脚本使用。

lib/Common.pm

package Common;

use strict;
use warnings;

use Exporter qw(import);
our @EXPORT_OK = qw( test_me );

sub test_me { print "Hello from ", __PACKAGE__, "\n" }

1;

当一个包是used 时,它的文件首先是required,然后在编译时运行模块的import 方法。调用者实际上是通过import 获取模块中定义的符号(函数和变量的名称),我们必须在模块中提供import 方法(或使用完全限定名称Module::function,在来电者)。

use Exporter 的行引入了 its import 例程,因此我们不必自己编写。对于旧版本的Exporter,这是通过继承使用的,通常是@ISA = ('Exporter')。请参阅文档。

然后通过@EXPORT_OK 提供符号。这需要调用者列出要使用的函数;默认情况下,它不会将任何内容“推送”到它们的命名空间中。还有 %EXPORT_TAG 很有帮助,特别是当调用者导入的符号列表变长时。


这实际上只是将当前working directory (.) 用于脚本目录的一般问题的一个示例:它不是;一般来说,它不是。

还有一点需要注意,从 5.26 版开始,出于安全原因,@INC 中的 .(当前目录)is not anymore。这也可能被向后移植到早期版本。

所以只需使用$RealBin,如图所示(1.51 版有一个重要的修复)。

【讨论】:

  • 我做到了,我尝试将 Common.pm 作为模块加载,请参阅我的 Edit2。
  • @snaggs 这不是编写模块的正确方法,因为您没有设置系统来导出符号。至于脚本,你为什么要使用Module::Load?设置模块后,您只需要use Common qw(functions);。 (你想用大写调用模块,Common.pm 这个模块。)如果你想切换到这个,请告诉我。但是对于初学者来说,require 行中的这种更改应该可以使它起作用。
  • 推荐use Exporter 'import'可能比推荐的继承方法更好。旧版本的 Exporter 不支持它,但继承 import 而不是导入它应该被视为那些不愿意或无法升级的解决方法。
  • @PerlDuck 这是一个合理的策略(同时放弃所有输入也是合理的)。这就是我使用@EXPORT_OK 的原因——它实际上并不导出东西(不更改符号表),但它确实使符号可用于导入,因此调用者可以决定。仍然可以选择不导入并使用完全限定名称。我没有看到 提供 的缺点。它不会对任何人强制执行任何操作。
  • @Borodin 我只找到了File::Path::Tiny,它调用了Acme::Tiny,它引用了a blog。仅略读亚当·肯尼迪(Adam Kenedy)提出的揭示规则。几乎不正式:(可能还有更多?
猜你喜欢
  • 1970-01-01
  • 2013-05-19
  • 2012-09-12
  • 1970-01-01
  • 2012-09-07
  • 2020-07-15
  • 2011-09-11
  • 1970-01-01
  • 2019-07-27
相关资源
最近更新 更多