我一直在学习Perl中的文件句柄,我很想知道是否有办法在程序运行时更改程序的源代码。例如,我创建了一个名为“dynamic.pl”的脚本,其中包含以下内容:
use strict;
use warnings;
open(my $append, ">>", "dynamic.pl");
print $append "print \"It works!!\\n\";\n";
此程序添加了行
print "It works!!\n";
到它自己的源文件的末尾,我希望一旦添加该行,它就会执行并输出“It works !!”
好吧,它确实将该行正确附加到源文件,但它并没有执行它。
所以我假设当perl执行一个程序,它将它加载到内存并从那里运行它,但我的问题是,有没有办法访问这个加载版本的程序,所以你可以有一个程序,可以你跑的时候改变自己吗?
答案 0 :(得分:2)
您需要的缺失部分是eval EXPR
。这将编译,"评估",任何字符串作为代码。
my $string = q[print "Hello, world!";];
eval $string;
此字符串可以来自任何来源,包括文件句柄。
它也不必是一个单一的陈述。如果要修改程序的运行方式,可以替换其子程序。
use strict;
use warnings;
use v5.10;
sub speak { return "Woof!"; }
say speak();
eval q[sub speak { return "Meow!"; }];
say speak();
您将收到Subroutine speak redefined
警告。它可以用no warnings "redefine"
来压制。
{
# The block is so this "no warnings" only affects
# the eval and not the entire program.
no warnings "redefine";
eval q[sub speak { return "Shazoo!"; }];
}
say speak();
显然这是一个主要的安全漏洞。这里有很多很多东西要考虑,答案太长了,我强烈建议你不要这样做,找到一个更好的解决方案来解决你试图解决的问题方式。
减轻潜在损害的一种方法是使用Safe模块。这与eval
类似,但限制了可用的内置函数。它绝不是安全问题的灵丹妙药。
答案 1 :(得分:2)
发出有关各种问题的警告,您可以重新加载模块。
有一些软件包,例如Module::Reload。然后,您可以编写要在模块中更改的代码,在运行时更改源,并重新加载。
您可以手动删除%INC
,然后require
,例如
# change source code in the module ...
delete $INC{'ModuleWithCodeThatChages.pm'};
require ModuleWithCodeThatChanges;
我能想到这样做的唯一原因是实验和游戏。否则,做这样的事情会有各种各样的问题,无论你的目标是什么,还有其他方法可以实现它。
注意问题确实指定了文件句柄。但是,我并不认为这与我认为是问题的核心,即在运行时修改代码有关。
答案 2 :(得分:0)
源文件在编译后不会被使用。
你可以eval
。
use strict;
use warnings;
my $code = <<'__EOS__'
print "It works!!\n";
__EOS__
open(my $append_fh, ">>", "dynamic.pl")
or die($!);
print($append_fh $code);
eval("$code; 1")
or die($@);
答案 3 :(得分:-1)
这里几乎肯定有更好的方法来实现你的最终目标。但是,如果需要返回值,可以递归地进行exec()或system()调用。一定要设置一些条件或多米诺骨牌会继续下降。再说一遍,你应该重新考虑这个,除非它只是某种做法,或者我不明白!
每次调用都应该执行文件的最新状态;也请务必在每次通话前关闭文件。
即,
exec("dynamic.pl");
或
my retval;
retval = system("perl dynamic.pl");
永远不要使用eval。