我已经创建了一个脚本,用于在给定输入文件夹后验证xml文件。它应该从输入目录中grep xml文件,然后整理出xml文件并检查条件。但是它会抛出一个not Open at line , <STDIN> line 1
的命令。
但是它将创建一个空的日志文件。
由于排序时遇到numeric
错误,请对此进行评论。
所以我需要输入位置,脚本应该检查xml文件并在提到的日志文件中引发错误。
有人可以帮助吗?
脚本
#!/usr/bin/perl
# use strict;
use warnings;
use Cwd;
use File::Basename;
use File::Path;
use File::Copy;
use File::Find;
print "Enter the path: ";
my $filepath = <STDIN>;
chomp $filepath;
die "\n\tpleas give input folder \n" if(!defined $filepath or !-d $filepath);
my $Toolpath = dirname($0);
my $base = basename($filepath);
my $base_path = dirname($filepath);
my ($xmlF, @xmlF);
my @errors=();
my @warnings=();
my @checkings=();
my $ecount=0;
my $wcount=0;
my $ccount=0;
my ($x, $y);
my $z="0";
opendir(DIR,"$filepath");
my @xmlFiles = grep{/\.xml$/} readdir(DIR);
closedir(DIR);
my $logfile = "$base_path\\$base"."_Err.log";
# @xmlF=sort{$a <=> $b}@xmlFiles;
@xmlF=sort{$a cmp $b}@xmlFiles;
open(OUT, ">$logfile") || die ("\nLog file couldnt write $logfile :$!");
my $line;
my $flcnt = scalar (@xmlF);
for ($x=0; $x < $flcnt; $x++)
{
open IN, "$xmlF[$x]" or die "not Open";
print OUT "\n".$xmlF[$x]."\n==================\n";
print "\nProcessing File $xmlF[$x] .....\n";
local $/;
while ($line=<IN>)
{
while ($line=~m#(<res(?: [^>]+)? type="weblink"[^>]*>)((?:(?!</res>).)*)</res>#igs)
{
my $tmp1 = $1; my $tmp2 = $&; my $pre1 = $`;
if($tmp1 =~ m{ subgroup="Weblink"}i){
my $pre = $pre1.$`;
if($tmp2 !~ m{<tooltip><\!\[CDATA\[Weblink\]\]><\/tooltip>}ms){
my $pre = $pre1.$`;
push(@errors,lineno($pre),"\t<tooltip><\!\[CDATA\[Weblink\]\]></tooltip> is missing\n");
}
}
}
foreach my $warnings(@warnings)
{
$wcount = $wcount+1;
}
foreach my $checkings(@checkings)
{
$ccount = $ccount+1;
}
foreach my $errors(@errors)
{
$ecount = $ecount+1;
}
my $count_err = $ecount/2;
print OUT "".$count_err." Error(s) Found:-\n------------------------\n ";
print OUT "@errors\n";
$ecount = 0;
my $count_war = $wcount/2;
print OUT "$count_war Warning(s) Found:-\n-------------------------\n ";
print OUT "@warnings\n";
$wcount = 0;
my $count_check = $ccount/2;
print OUT "$count_check Checking(s) Found:-\n-------------------------\n ";
print OUT "@checkings\n";
$wcount = 0;
undef @errors;
undef @warnings;
undef @checkings;
close IN;
}
}
答案 0 :(得分:6)
readdir
返回无路径的裸文件名。
因此,当您继续打开那些文件时,您需要在readdir
返回的名称之前加上readdir
从中读取文件的目录名称,这里$filepath
。或立即构建完整路径名
use warnings;
use strict;
use feature 'say';
use File::Spec;
print "Enter the path: ";
my $filepath = <STDIN>;
chomp $filepath;
die "\nPlease give input folder\n" if !defined $filepath or !-d $filepath;
opendir(my $fh_dir, $filepath) or die "Can't opendir $filepath: $!";
my @xml_files =
map { File::Spec->catfile($filepath, $_) }
grep { /\.xml$/ }
readdir $fh_dir;
closedir $fh_dir;
say for @xml_files;
我使用File::Spec来可移植地拼凑文件名。
以下是有关代码的一些注释。请注意,这通常是在代码审查中完成的,但我觉得这里是必需的。
首先:首先声明一长串变量。实际上,声明尽可能小的范围很重要。事实证明,这些变量中的大多数确实可以在使用它们的地方声明,如下面的注释所示。
使用
最好找到可执行文件的位置use FindBin qw($RealBin);
其中$RealBin
也解析链接(与$Bin
相对,也可用)
在声明时将()
分配给数组没有任何作用;它与普通my @errors;
完全相同。他们也可以一起走,my (@errors, @warnings, @checks);
。如果数组中包含某些内容,那么= ()
会将其清除,那么清空数组的好方法是什么
分配"0"
会使变量成为字符串。虽然Perl通常会根据需要在字符串和数字之间进行转换,但是如果需要数字,则使用数字my $z = 0;
词汇文件句柄(open my $fh, ...
)比全局句柄(open FH, ...
)
我不理解有关排序中“ 数字错误”的注释。 cmp
operator按字典顺序排序,对于数字排序,请使用<=>
在scalar context中使用数组时–例如,当分配给标量时–返回元素数。因此,不需要scalar
而是my flcnt = @xmlF;
对于数组索引的迭代,请使用$#ary
的{{1}}的最后一个元素的索引,用于
@ary
但是如果索引没有任何用处(我看不到),则遍历元素
foreach my $i (0..$#xmlF) { ... }
当您检查文件foreach my $file (@xmlF) { ... }
打印错误 $!,open
时。这是在代码的其他地方完成的,应该始终这样做。
open ... or die "... : $!";
取消了input record separator的设置,这使得以下内容读取了整个文件。如果打算这样做,那么local $/;
并不是一个好名字。另请注意,可以在条件$line
我无法评论正则表达式,因为我不知道它应该完成什么,但是它很复杂。有机会简化所有步骤吗?
while (my $line = <$fh>) { }
循环系列仅计算出这些数组的元素数量;那么就不需要循环,只需foreach
(等等)。这也使您可以将这些计数器变量的声明保持在最小范围内。
不需要my $ecount = @errors;
(等),因为这些数组对每个文件都有效,因此您可以在循环内声明它们,每次迭代时都要重新声明(并且作用域最小)。当您希望清空数组时,最好undef @errors;
比@ary = ();
做。