以下Perl脚本按预期输出“SUCCESS”:
use Fcntl qw(:DEFAULT :flock);
sysopen(LF, "test.txt", O_RDONLY | O_CREAT) or die "SYSOPEN FAIL: $!";
if(flock(LF, LOCK_EX)) { print "SUCCESS.\n"; }
else { print "FAIL: $!\n"; }
但现在,用
替换第一行require "testlib.pl";
其中testlib.pl包含
use Fcntl qw(:DEFAULT :flock);
1;
现在,奇怪的是,脚本失败了,就像这样:
FAIL: Bad file descriptor
问题:为什么?
增加:
现在我知道为什么 - 谢谢! - 我想知道解决这个问题的最佳方法是什么:
use Fcntl
两次,一次在主脚本中,一次在所需的库中(主脚本和库都需要它)。答案 0 :(得分:3)
通过上述use
,您剥夺了Perl解析器O_RDONLY
等人的知识。是无参数子程序。在这种情况下你必须更加冗长:
sysopen(LF, "test.txt", O_RDONLY() | O_CREAT()) or die "SYSOPEN FAIL: $!";
if(flock(LF, LOCK_EX())) { print "SUCCESS.\n"; }
编辑:为了进一步阐述,没有括号,O_RDONLY
和O_CREAT
被解释为裸字(字符串),它们的行为与二进制时的预期不同。 'ed together:
$ perl -le 'print O_RDONLY | O_CREAT'
O_SVOO\Y
(个别字符按位或按字母方式。)
在这种情况下,字符串“O_SVOO \ Y”(或系统中的任何内容)被解释为数字0到sysopen
,因此只要O_RDONLY
,它就会工作是0(典型)并且文件已经存在(因此O_CREAT
是多余的)。但fcntl
显然不是对非数字参数的宽容:
$ perl -e 'flock STDOUT, "LOCK_EX" or die "Failed: $!"'
Failed: Bad file descriptor at -e line 1.
类似地:
$ perl -e 'flock STDOUT, LOCK_EX or die "Failed: $!"'
Failed: Bad file descriptor at -e line 1.
然而:
$ perl -e 'use Fcntl qw(:flock); flock STDOUT, LOCK_EX or die "Failed: $!"'
(no output)
最后,请注意use strict
提供了许多有用的线索。
答案 1 :(得分:2)
行use Fcntl qw(:DEFAULT :flock);
不仅为您加载Fcntl库,还将一些符号导出到脚本的命名空间中。如果你将它移到另一个范围,那么常量O_RDONLY,O_CREAT,LF和LOCK_EX将不再可用,并且你的代码将不会做同样的事情 [但你仍然可以访问它们,如果你知道他们最终进入了什么命名空间 - 因为它是一个执行导出的脚本,你可以调用& main :: NAME或简单地和& NAME,但是你必须知道另一个文件正在用它的代码做什么,这不是很干净] 。
EXPORTED SYMBOLS下的文档中描述了这一点:
默认情况下,系统的F_ *和O_ *常量(例如,F_DUPFD和O_CREAT)和FD_CLOEXEC常量将导出到您的命名空间中。
您可以使用标签“:flock”请求提供flock()常量(LOCK_SH,LOCK_EX,LOCK_NB和LOCK_UN)。见出口商。
如果添加行
use strict;
use warnings;
到脚本的顶部,您将获得更多信息性的错误消息,例如“Name”main :: O_RDONLY“仅使用一次:可能的类型在行...”,这将为您提供这些常量定义的线索不再可见。
编辑:在回答您的问题时,最佳做法是#1,包含 每个需要它的文件中的use语句。请参阅perldoc -f use - Fcntl库只包含一次,但每次需要时都会调用import(),这就是你想要的。
答案 2 :(得分:0)
用法相当于:
BEGIN { require Module; Module->import( LIST ); }
保证在代码开始执行之前导入功能可用。当你用require替换use时,它只是在程序中的词汇点读取代码。