Perl打印到文件错误

时间:2013-06-27 18:04:56

标签: perl perl-module

我是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;

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

#!/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

可能导致这种情况的原因是什么? 谢谢,

-rusty

2 个答案:

答案 0 :(得分: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: $!";
    

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

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

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

  • 您已成功实施了一些开始在START标记处复制的扭曲逻辑。但是,您不会停留在END。对于这样的东西,可以使用触发器 - 运算符 ..:它需要两个操作数,它们是任意表达式。运算符返回false直到第一个操作数为true,并且在第二个操作数返回true之后保持为true。如果一个操作数是常量整数,则将其解释为行号。因此,脚本

    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
    3. 我们可以通过在终止条件下测试文件结尾来缓解问题#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
      

答案 1 :(得分:0)

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

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