我的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 strict
和use warnings
但我没有收到任何错误消息。
该部分是脚本中的一个自包含数据库。我这样做是为了使目录中的其他文件数量尽可能低。
答案 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_block
(start
本身就是用词不当)
避免不必要的评论,例如
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;