0

我对 Perl 比较陌生,正在尝试将几个 .pm 文件组合到一个脚本中。大多数模块都可以很好地复制,但有些模块在到达文件末尾时出现错误,但脚本会继续打印。以下是代码示例:

$copy_line = 0;
sysopen(FILE, $file_path, O_WRONLY | O_CREAT, 0711);
sysopen(MODULE, $module_path, O_RDONLY | O_EXCL);

while(<MODULE>)
{
  my $line = $_;
  if(($line ne "# START\n") and ($copy_line eq 0))
  {
  }
  else
  {
    print FILE "$line";
    $copy_line = 1;
  }
}

close FILE;
close MODULE;

每个模块都有开始和结束标签,我不复制任何使用语句,所以我知道什么时候停止复制。该模块的一个例子是

#!/usr/bin/perl
# START
some code to copy over
some more code to copy
even more code to copy
# END

在某些文件中发生的情况是我看到了结束标记,然后是模块中的重复代码。输出看起来像

# START
some code to copy over
some more code to copy
even more code to copy
# END
code to copy
even more code to copy
# END

这可能是什么原因造成的?谢谢,

-生锈的

4

2 回答 2

2

您的脚本存在各种问题:

  • 您没有显示整个脚本;O_WRONLY默认情况下不存在类似的常量。

  • use strict; use warnings;因此,您可能在脚本的开头没有这样做。这对于收到有关错误或可能的错误的警告是必要的。

  • strict模式要求您声明所有变量。您可以使用my关键字来执行此操作,例如my $copy_line = 0.

  • 切勿使用sysopen,除非您完全了解其open工作原理以及为什么它不是特定情况下的最佳选择。考虑到我没有那种水平的知识,我想我们会坚持正常的open

    接受一个变量、open一个模式和一个文件名,比如

    open my $file, "<", $filename;
    

    我鼓励您use autodie进行自动错误处理,否则您应该这样做

    open my $file, "<", $filename or die "Can't open $filename: $!";
    

    where$!包含错误的原因。您可以为 open 指定各种模式,这些模式以 shell 重定向运算符为模型。重要的是:<读取、>写入(或创建)、>>追加、|-将管道写入命令、-|从命令读取管道。

  • eq运算符测试字符串是否相等。如果要测试数字是否相等,请使用==运算符。

  • if (COND) {} else { STUFF }宁可写成unless (COND) {STUFF}

  • START您已经成功实现了一些在标记处开始复制的扭曲逻辑。但是,您不会停留在END. 对于这样的事情,可以使用触发器运算符:它需要两个操作数,它们是任意表达式。 ..运算符在第一个操作数为真之前返回假,在第二个操作数返回真之前保持真。如果一个操作数是一个常数整数,它被解释为一个行号。因此,脚本

    while (<>) {
      print if 5 .. 10;
    }
    

    打印包含输入的第 5-10 行。

    对于您的问题,您可能应该使用匹配开始和结束标记的正则表达式:

    while (<>) {
      print if /^ \s* # \s* START/x .. /^ \s* # \s* END/x
    }
    

    我在这里假设您知道正则表达式,但如果需要,我可以添加解释。

    如果在没有操作数的情况下使用 readline 运算<>符,它将获取脚本的命令行参数,打开它们,然后按顺序读取它们。如果未提供任何参数,则使用 STDIN。

    这允许灵活的小脚本。代码可以总结在命令行oneliner

    $ perl -ne'print if /^\s*#\s*START/../^\s*#\s*END/' INPUT-FILE1 INPUT-FILE2 >OUTPUT
    

    这有两个问题:

    1. 它也打印出开始/结束标记
    2. 如果文件不包含# END,则将完整打印下一个文件,直到# END找到下一个文件。

    我们可以通过在终止条件下测试文件结尾来缓解问题 #2:

    print if /^\s*#\s*START/ .. (/^\s*#\s*END/ or eof);
    

    问题 #1 稍微复杂一些;我会为此重新引入一个标志:

    my $print_this = 0;
    
    while (<>) {
      if (/^\s*#\s*END/ or eof) {
          $print_this = 0;
      } elsif ($print_this) {
          print;
      } elsif (/^\s*#\s*START/) {
          $print_this = 1;
      }
    }
    

    部分测试用例:

    $ perl -e'
      my $print_this = 0;
      while (<>) {
        if    (/^\s*#\s*END/ or eof) { $print_this = 0 }
        elsif ($print_this)          { print           }
        elsif (/^\s*#\s*START/)      { $print_this = 1 }
      }' <<'__END__'
    no a 1
    no a 2
      # START
    yes b 1
    yes b 2
    yes b 3
    #END
    no c 1
    no c 2
    # START
    yes d 1
     #    END
    no e 1
    __END__
    

    输出:

    yes b 1
    yes b 2
    yes b 3
    yes d 1
    
于 2013-06-27T19:33:45.983 回答
0

如果您在不修改其内容的情况下复制文件,您应该查看File::Copy http://perldoc.perl.org/File/Copy.html

File::Copy是一个标准模块,与 Perl 一起安装。有关标准模块的列表,请参阅perldoc perlmodlib http://perldoc.perl.org/perlmodlib.html#Standard-Modules

于 2013-06-27T18:14:18.730 回答