Code不适用于Linux Perl解释器,但使用Strawberry Perl

时间:2018-01-09 11:58:50

标签: perl

我的Perl程序的目的是找到一个特定的部分 在程序代码本身内。该部分以# Start of section和。{ 以# End of section结尾。

我用 Windows 开发了脚本 Strawberry Perl 并且它起作用了。

现在我正在尝试在 Linux 计算机上执行我的程序,它不起作用。

open( LIST_FILE, "<$listFilename" ) || die "List file not found!\n";

while ( <LIST_FILE> ) {

    chomp( $currentLine = $_ );    # Chop the \n

    if ( $currentLine eq "# End of section" ) {    # Search for the ENDLINE
        $startTemplateSection = 0;                 # ENDLINE found
    }

    if ( $startTemplateSection == 1 ) {            # Start pushing when STARTLINE is found
        push( @listFileLines, $currentLine );      # Attach the current line to the FIRST array
    }

    if ( $currentLine eq "# Start of section" ) {    # Search for the STARTLINE
        $startTemplateSection = 1;                   # STARTLINE found
    }
}

close( LIST_FILE );

更新

抱歉,我认为我的问题更清楚了。问题出在if

我尝试在Perl文件中检查这些行。用 Strawberry Perl if正常工作,部分内的行被推送到@listFileLines数组中。使用 Linux解释器$startTemplateSection永远不会达到1,因此不会被推送。

use strictuse warnings但我没有收到任何错误消息。

该部分是脚本中的一个自包含数据库。我这样做是为了使目录中的其他文件数量尽可能低。

2 个答案:

答案 0 :(得分:1)

问题几乎可以肯定,您已将程序文件从Windows系统逐字复制到Linux

Windows文本行结尾为CR LF,并且perl会在读取文本时删除CR。之后,chomp删除剩余的LF,留下裸线

在Linux上,任何尾随CR都会留在原位。因此,在chomp删除LF之后,CR仍然存在,导致字符串比较失败

围绕这个

有几种方法
  • 使用s/\s+\z//代替chomp。这也将删除每行末尾的任何(不可见的)尾随空格

  • 使用s/\R\z//代替chomp。这将删除任何形式的行结尾,无论平台

  • 以Windows模式打开文件

    open my $list_fh, '<:crlf', $list_filename or die "List file not found: $!";
    
  • 将默认open设置为文件顶部的Windows模式

    use open IN  => ':crlf'
    

    然后正常呼叫open

您的代码中还有很多可以改进的内容

  • 本地Perl变量传统上使用snake_case命名,而大写字母则保留用于全局标识符和模块名称。您可能对camelCase更熟悉,但更有经验的Perl社区会感谢您改变自己的风格,尤其是在寻求代码帮助时。另请注意,许多第一语言不是英语的程序员发现阅读骆驼案件要困难得多

  • 您应该使用三参数形式的open lexical 文件句柄

    您应该在$!字符串中包含内置变量die的值,该字符串确切地告知open失败的原因。 open未找到

    而失败的原因有很多

    所以

    open( LIST_FILE, "<$listFilename" ) || die "List file not found!\n";
    

    应该是

    open my $list_fh, '<', $list_filename or die "Couldn't open list file: $!";
    
  • 冗长的变量名通常只会使代码更难以阅读。 $startTemplateSection之类的内容可能只是$in_blockstart本身就是用词不当)

  • 避免不必要的评论,例如

    chomp( $currentLine = $_ );    # Chop the \n
    

    分散注意力只是为了告诉我我已经知道的事情

    我知道为什么,但如果你认为这很明显,那么你写的评论肯定是微不足道的吗?

  • 所有声明应尽可能 late ,最好是在首次使用该值的时候

以下是重构代码的方法

open my $fh, '<', $list_filename or die "Couldn't open list file: $!";

my $in_block = 0;
my @file;

while ( my $line = <$fh> ) {

    chomp $line;

    $in_block = 0 if $line eq '# End of section';

    push @file, $line if $in_block;

    $in_block = 1 if $line eq '# Start of section';
}

答案 1 :(得分:0)

作为simbabque mentioned,你应该 检查你的文件格式。您的输入文件可能有DOS换行符(\r\n)。 chomp将从字符串末尾删除$INPUT_RECORD_SEPARATOR(在Unix下,默认值为\n)。如果你的文件有DOS换行符,它会在你的字符串末尾留下\r,你的'eq'检查将为false,因为if条件中的字符串不包含\r

我修改了你的代码,从字符串末尾删除所有尾随空格(包括换行符)。因此它可能会再次发挥作用。

use strict;
use warnings;


open( my $LIST_FILE, "<", $listFilename ) or die "Failed to open '$listFilename' for reading ($!)!\n";

while ( my $currentLine = readline $LIST_FILE ) {

    $currentLine =~ s/\s*\z//; # remove trailing whitespaces and newline chars, such as \r\n or \n

    if ( $currentLine eq "# End of section" ) {    # Search for the ENDLINE
        $startTemplateSection = 0;                 # ENDLINE found
    }

    if ( $startTemplateSection == 1 ) {            # Start pushing when STARTLINE is found
        push( @listFileLines, $currentLine );      # Attach the current line to the FIRST array
    }

    if ( $currentLine eq "# Start of section" ) {    # Search for the STARTLINE
        $startTemplateSection = 1;                   # STARTLINE found
    }
}

close $LIST_FILE;