【问题标题】:How does Perl interact with the scripts it is running?Perl 如何与它正在运行的脚本交互?
【发布时间】:2011-04-06 19:02:55
【问题描述】:

我有一个 Perl 脚本,它运行一个能够编辑文件系统的不同实用程序(称为Radmind,对于那些感兴趣的人)。 Perl 脚本监视此进程的输出,因此它将在整个情况下运行。

如果脚本运行的实用程序尝试编辑脚本文件本身,即用更新的版本替换它,会发生什么情况? Perl 是否会在执行开始时加载脚本和任何链接库,然后忽略脚本文件本身,除非被明确告知要搞乱它?或者,是否会彻底崩溃,执行可能会失败也可能不会失败,具体取决于新文件与正在运行的文件有何不同?

或者完全是别的什么?如果这属于超级用户,我深表歉意——这对我来说似乎是一个灰色地带。

【问题讨论】:

    标签: perl macos scripting file


    【解决方案1】:

    Perl 脚本是读入内存、在内存中编译的简单文本文件,文本文件脚本不再被读取。 (例外是编译后进入词法范围的模块以及在某些情况下 doeval 语句......)

    有一个众所周知的实用程序可以利用这种行为。查看 CPAN 及其许多版本,它们可能位于您的 /usr/bin 目录中。系统上的每个 Perl 版本都有一个 CPAN 版本。当新版本的 CPAN 本身可用时,CPAN 会感知,询问您是否要安装它,如果您说“y”,它将下载新版本并在您离开的地方重新生成,而不会丢失任何数据。

    这个逻辑不难理解。阅读 /usr/bin/CPAN,然后遵循与 $Config::Config{version} 将在您的系统上生成的内容相关的个性化版本。

    干杯。

    【讨论】:

      【解决方案2】:

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

      use strict;
      use warnings;
      use English qw<$PROGRAM_NAME>;
      
      open my $ph, '>', $PROGRAM_NAME;
      print $ph q[print "!!!!!!\n";];
      close $ph;
      do $PROGRAM_NAME;
      

      ...不要这样做!!!

      【讨论】:

        【解决方案3】:

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

        [1] BEGIN 块将在编译期间运行代码,而诸如 evalrequire 之类的命令将在运行时编译附加代码

        [2] 最有可能使用evaldo,因为requireuse 检查文件是否已经加载,如果已经加载则忽略它。

        【讨论】:

        • 这甚至不如您的答案那么简单,您可以将代码附加到文件末尾的 BEGIN 块中,它将包含在程序中。至少在我目前可以访问的 perl 版本中,它不会在开始解析之前读取整个文件,并且在解析完右大括号后立即执行 BEGIN 块。这种行为可能非常依赖于操作系统。
        【解决方案4】:

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

        #! /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:仍在运行!

        【讨论】:

          【解决方案5】:

          您的 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";
          

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

          【讨论】:

            【解决方案6】:

            脚本文件被一次读入内存。之后,您可以从另一个实用程序(或从 Perl 脚本本身)编辑该文件。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2016-04-10
              • 1970-01-01
              • 2012-06-15
              • 1970-01-01
              • 1970-01-01
              • 2019-09-18
              • 1970-01-01
              相关资源
              最近更新 更多