Perl如何与其正在运行的脚本进行交互?

6

我有一个运行Perl脚本的工具(叫做Radmind,对于那些感兴趣的人来说),它有修改文件系统的能力。Perl脚本监视此进程的输出,因此在整个过程中它将一直运行。

如果工具试图编辑脚本文件本身,例如用新版本替换它,会发生什么情况呢?Perl是否在执行开始时加载脚本和任何链接库,然后忽略脚本文件本身,除非明确告知要操作它?或者,所有东西都乱了,可能会根据新文件与正在运行的文件的差异而失败或成功?

或者也许是其他完全不同的情况?如果这篇文章不适合,请谅解——对我来说似乎是一个灰色地带。

6个回答

7
这并不像pavel的回答所说的那样简单,因为Perl实际上没有干净的“先编译源代码,然后运行编译后的代码”的区分[1],但基本观点还是正确的:每个源文件在编译或执行其中任何代码之前都会从磁盘上完全读取,并且对源文件的任何后续更改除非你明确指示perl重新加载文件并执行新版本的代码[2],否则不会影响正在运行的程序。

[1] BEGIN块将在编译期间运行代码,而像evalrequire这样的命令将在运行时编译额外的代码。

[2] 最可能使用evaldo,因为requireuse会检查文件是否已经加载,并在已加载时忽略它。


1
这甚至不像你的答案那样简单,你可以在文件末尾添加代码,在BEGIN块中它将被包含在程序中。至少在我目前可以访问的perl版本中,它不会在开始解析之前读取整个文件,并且BEGIN块会在解析到闭合括号时立即执行。这种行为可能与操作系统有关。 - Ven'Tatsu

3

为了一个有趣的演示,请考虑

#! /usr/bin/perl

die "$0: where am I?\n" unless -e $0;

unlink $0 or die "$0: unlink $0: $!\n";

print "$0: deleted!\n";
for (1 .. 5) {
  sleep 1;
  print "$0: still running!\n";
}

示例运行:

$ ./prog.pl
./prog.pl:已删除!
./prog.pl:仍在运行!
./prog.pl:仍在运行!
./prog.pl:仍在运行!
./prog.pl:仍在运行!
./prog.pl:仍在运行!

2
你的Perl脚本将首先被编译,然后运行;因此,在脚本运行时更改它不会改变正在运行的已编译代码。
考虑以下示例:
#!/usr/bin/perl

use strict;
use warnings;

push @ARGV, $0;
$^I = '';

my $foo = 42;
my $bar = 56;

my %switch = (
    foo => 'bar',
    bar => 'foo',
);

while (<ARGV>) {
    s/my \$(foo|bar)/my \$$switch{$1}/;
    print;
}

print "\$foo: $foo, \$bar: $bar\n";

并且在多次运行时观察结果。


0

正如其他人所说,脚本被读入内存,编译并运行。GBacon表明您可以删除文件并运行它。下面的代码显示您可以更改文件并执行它以获取新的行为。

use strict;
use warnings;
use English qw<$PROGRAM_NAME>;

open my $ph, '>', $PROGRAM_NAME;
print $ph q[print "!!!!!!\n";];
close $ph;
do $PROGRAM_NAME;

...不要这样做!!!


0

脚本文件只需读取一次即可加载到内存中。之后,您可以从其他实用程序或Perl脚本本身编辑该文件(如果需要)。


0
Perl脚本是简单的文本文件,读入内存后在内存中编译,然后不再读取文本文件脚本(例外情况是一些模块在编译后进入词法作用域以及还有一些情况下使用doeval语句...)。
已知有一个利用这种行为的实用程序。请参阅CPAN及其许多版本,该程序可能位于您的/usr/bin目录中。每个Perl版本都有一个相应的CPAN版本。当CPAN自身的新版本可用时,CPAN将检测到,询问是否要安装它,并且如果您回答“y”,它将下载更新版本并在您离开的地方重新启动自己,而不会丢失任何数据。
这个逻辑不难理解。请阅读/usr/bin/CPAN,然后关注与您系统上$Config::Config{version}生成相关的个性化版本。
干杯。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接