在 Perl 中使用文件句柄主动更改 运行 代码

Using filehandles in Perl to alter actively running code

我一直在学习 Perl 中的文件句柄,我很好奇是否有一种方法可以在 运行ning 时更改程序的源代码。例如,我创建了一个名为 "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 执行一个程序时,它将它加载到内存并从那里 运行s 它,但我的问题是,有没有办法访问程序的这个加载版本所以你可以拥有一个可以随着你的改变而自我改变的程序吗?运行?

您需要的缺失部分是 eval EXPR。这编译,"evaluates",任何字符串作为代码。

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 但限制了可用的内置函数。绝不是解决安全问题的灵丹妙药。

几乎肯定有更好的方法来实现您的最终目标。但是,您可以递归地进行 exec() 或 system() 调用——后者如果您需要 return 值。一定要设置一些条件,否则多米诺骨牌会不断倒下。再一次,你应该重新考虑这个,除非它只是某种练习,或者我不明白!

每次调用都应该执行文件的最新状态;也一定要在每次调用前关闭文件。

exec("dynamic.pl");

my retval; 
retval = system("perl dynamic.pl");

永远不要使用 eval。

有了关于各种问题的警告,您可以重新加载模块。

有相应的软件包,例如 Module::Reload。然后您可以编写您打算在模块中更改的代码,在运行时更改源代码,然后重新加载它。

您可以手动从 %INC 中删除它,然后 require,例如

# ... change source code in the module ...
delete $INC{'ModuleWithCodeThatChages.pm'};
require ModuleWithCodeThatChanges;

我能想到的这样做的唯一原因就是实验和玩耍。否则,做这样的事情会有各种各样的顾虑,无论你的目标是什么,都有其他方法可以实现。

注意 问题确实指定了文件句柄。但是,我认为这与我认为是在运行时修改代码的问题的核心没有真正的关系。

源文件编译后未使用

你可以 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($@);