使用Perl中的文件句柄来更改正在运行的代码

时间:2016-05-08 03:28:20

标签: perl file-handling

我一直在学习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执行一个程序,它将它加载到内存并从那里运行它,但我的问题是,有没有办法访问这个加载版本的程序,所以你可以有一个程序,可以你跑的时候改变自己吗?

4 个答案:

答案 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。