Using filehandles in Perl to alter actively running code

你。 提交于 2020-01-05 05:37:05

问题


I've been learning about filehandles in Perl, and I was curious to see if there's a way to alter the source code of a program as it's running. For example, I created a script named "dynamic.pl" which contained the following:

use strict;
use warnings;

open(my $append, ">>", "dynamic.pl");
print $append "print \"It works!!\\n\";\n";

This program adds the line

print "It works!!\n";

to the end of it's own source file, and I hoped that once that line was added, it would then execute and output "It works!!"

Well, it does correctly append the line to the source file, but it doesn't execute it then and there.

So I assume therefore that when perl executes a program that it loads it to memory and runs it from there, but my question is, is there a way to access this loaded version of the program so you can have a program that can alter itself as you run it?


回答1:


With a warning about all kinds of issues, you can reload modules.

There are packages for that, for example, Module::Reload. Then you can write code that you intend to change in a module, change the source at runtime, and have it reloaded.

By hand you would delete that from %INC and then require, like

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

The only reason I can think of for doing this is experimentation and play. Otherwise, there are all kinds of concerns with doing something like this, and whatever your goal may be there are other ways to accomplish it.

Note   The question does specify a filehandle. However, I don't see that to be really related to what I see to be the heart of the question, of modifying code at runtime.




回答2:


The missing piece you need is eval EXPR. This compiles, "evaluates", any string as code.

my $string = q[print "Hello, world!";];
eval $string;

This string can come from any source, including a filehandle.

It also doesn't have to be a single statement. If you want to modify how a program runs, you can replace its subroutines.

use strict;
use warnings;
use v5.10;

sub speak { return "Woof!"; }
say speak();

eval q[sub speak { return "Meow!"; }];
say speak();

You'll get a Subroutine speak redefined warning from that. It can be supressed with 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();

Obviously this is a major security hole. There is many, many, many things to consider here, too long for an answer, and I strongly recommend you not do this and find a better solution to whatever problem you're trying to solve this way.

One way to mitigate the potential for damage is to use the Safe module. This is like eval but limits what built in functions are available. It is by no means a panacea for the security issues.




回答3:


The source file isn't used after it's been compiled.

You could just eval it.

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



回答4:


There's almost definitely a better way to achieve your end goal here. BUT, you could recursively make exec() or system() calls -- latter if you need a return value. Be sure to setup some condition or the dominoes will keep falling. Again, you should rethink this, unless it's just practice of some sort, or maybe I don't get it!

Each call should execute the latest state of the file; also be sure to close the file before each call.

i.e.,

exec("dynamic.pl"); or

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

Don't use eval ever.



来源:https://stackoverflow.com/questions/37095921/using-filehandles-in-perl-to-alter-actively-running-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!