1

我正在使用 Perl(基于 POE)开发一个机器人,到目前为止一切都很好,但我不知道如何添加一个!jsor!perl命令来评估相应的代码并返回一行输出以打印到通道中. 我找到了App::EvalServer但我不知道如何使用它。

谢谢你的帮助!

4

2 回答 2

3

App::EvalServer模块附带一个二进制文件,可作为独立应用程序运行。你不要把它放在你的程序中,而是自己运行它。它打开一个端口,您可以在其中将代码作为 json 字符串传递。这对我来说也不是一个好主意。

您可能想查看另一个名为Safe的模块。我建议您在对此进行任何操作之前通读完整的文档以及Opcode的文档(链接在文档中)。如果您评估任意代码,您可能会造成严重损害!永远别忘了。


更新:

下面是一个示例,说明如何捕获 ed 代码的输出printsay来自evaled 代码的输出。您可以使用openwith a variable 使printed 输出始终转到该变量。如果你之后切换回来,你可以在你的 var 中使用捕获的输出。这称为内存文件

use strict; use warnings;
use feature 'say'; 
use Safe;

# Put our STDOUT into a variable
my $printBuffer;
open(my $buffer, '>', \$printBuffer);
# Everything we say and print will go into $printBuffer until we change it back
my $stdout = select($buffer);

# Create a new Safe
my $compartment = new Safe;
$compartment->permit(qw(print)); # for testing

# This is where the external code comes in:
my $external_code = qq~print "Hello World!\n"~;

# Execute the code
my $ret = $compartment->reval($external_code, 1);

# Go back to STDOUT
select($stdout);

printf "The return value of the reval is: %d\n", $ret;
say "The reval's output is:";
say $printBuffer;

# Now you can do whatever you want with your output
$printBuffer =~ s/World/Earth/;
say "After I change it:";
say $printBuffer;

免责声明:使用此代码需要您自担风险!


更新 2:经过长时间的聊天讨论,这就是我们想出的。它实现了一种超时来停止执行,如果reval需要很长时间,例如由于无限循环。

#!/usr/bin/perl
use warnings;
use strict;
use Safe;
use Benchmark qw(:hireswallclock);

my ($t0, $t1); # Benchmark
my $timedOut = 0;
my $userError = 0;
my $printBuffer;
open (my $buffer, '>', \$printBuffer);
my $stdout = select($buffer);
my $cpmt = new Safe;
$cpmt->permit_only(qw(:default :base_io sleep));
eval
{
        local $SIG{'ALRM'} = sub { $timedOut = 1; die "alarm\n"};
        $t0 = Benchmark->new;
        alarm 2;
        $cpmt->reval('print "bla\n"; die "In the user-code!";');
#         $cpmt->reval('print "bla\n"; sleep 50;');
        alarm 0;
        $t1 = Benchmark->new;
        if ($@)
        {
                $userError = "The user-code died! $@\n";
        }
};
select($stdout);


if ($timedOut)
{
        print "Timeout!\n";
        my $td = timediff($t1, $t0);
        print timestr($td), "\n";
        print $printBuffer;
}
else
{
        print "There was no timeout...\n";
        if ($userError)
        {
                print "There was an error with your code!\n";
                print $userError;
                print "But here's your output anyway:\n";
                print $printBuffer;
        }
        else
        {
          print $printBuffer;
        }
}
于 2012-06-24T21:37:00.653 回答
2

看一下perl eval(),您可以将变量/字符串传递给它,它会像 perl 代码一样评估它。同样在 javascript 中,还有一个eval()函数执行类似的操作。

但是,不要在 perl 或 javascript 中评估任意代码,除非您可以在完全封闭的环境中运行它(即使那样,这仍然是一个坏主意)。很多人花费大量时间来防止这种情况发生。所以你就是这样做的,但你根本不想这样做。

于 2012-06-24T21:05:27.363 回答