我在perl脚本方面遇到了困难..我有一个包含循环的脚本,但是一旦获得退出状态为零,它就永远不会突破它。只有在初始检查时退出状态为1时,循环才会运行通过“if”声明。
my $a = "/home/vivek/generated_mdsum_reference.out";
my $b = "/home/vivek/generated_mdsum_new.out";
sub CHECK {
print "\n";
print "\n";
print "\n\tGenerating MD5SUM ....";
my $dumpfile = "/home/vivek/file_dump.dmp";
print "\n";
# my $md5sum = system("md5sum $dumpfile");
my $md5sum = `md5sum $dumpfile`;
print "\n";
print "\nChecksum: $md5sum.";
# Put checksum in file
my $ochksumfile = "/home/vivek/generated_mdsum_new.out";
open (my $fh, '>', "$ochksumfile") or die "no file:$!";
my $output = $md5sum;
die "$!" if $?;
$value = (split / /, "$output")[0];
print $fh $value;
my $status =compare($b, $a);
}
my $status =compare($b, $a);
if ( $status == 1 ){
do
CHECK;
until ($status == 0 ) {
print "\n\tfiles are now Ok. Exiting..";
print "\n\t";
}
我在那里设置的所有变量都运行正常,我只是在for循环中结束,它一直无休止地运行,我认为它无法通过,直到其余的函数“CHECK”
请帮帮我们。
答案 0 :(得分:1)
让我们看一下有问题的街区
my $status = compare($b, $a);
if ( $status == 1 ) {
do
CHECK;
until ($status == 0 ) {
print "\n\tfiles are now Ok. Exiting..";
print "\n\t";
}
无论你是否意味着,这相当于
my $status = compare($b, $a);
if ( $status == 1 ) {
do CHECK;
until ( $status == 0 ) {
print "\n\tfiles are now Ok. Exiting..";
print "\n\t";
}
所以until
循环的内容只是两个打印语句,它们不会改变$status
的值,所以它会永远循环
我认为你的意思是
my $status = compare($b, $a);
if ( $status == 1 ) {
do {
CHECK;
} until $status == 0;
print "\n\tfiles are now Ok. Exiting..";
print "\n\t";
}
将重复调用CHECK
,直到$status
设置为零
除 外,您始终在本地标识符中使用小写字符。大写字母保留用于包名称等全局标识符。在这种情况下,您无意中创建了CHECK
块
在运行的Perl程序的开头和结尾处执行五个特别命名的代码块。这些是
BEGIN
,UNITCHECK
,CHECK
,INIT
和END
块。这些代码块可以以sub为前缀,以提供子例程的外观(尽管这不被认为是好的样式)。应该注意的是,这些代码块并不真正作为命名子例程存在(尽管它们的外观)。实现这一目标的事实是,您可以在程序中拥有多个这些代码块,并且它们将在适当的时刻执行。因此,您无法按名称执行任何这些代码块。
因为“这些代码块并不真正作为命名子程序存在”你的程序在编译期间只会 调用CHECK
,后续的显式调用将会被忽略
因此,将子例程重命名为check
,并将代码更改为此
my $status = compare($b, $a);
if ( $status == 1 ) {
do {
CHECK;
} until $status == 0;
print "\n\tfiles are now Ok. Exiting..";
print "\n\t";
}
一切都很好
答案 1 :(得分:0)
我不明白为什么until循环应该停止。
简而言之,您在" CHECK"中获得了一个文件的md5总和。子。
sub CHECK {
open (my $fh, '>', "/home/vivek/generated_mdsum_new.out");
my $dump_file = "/home/vivek/file_dump.dmp";
my $md5sum = `md5sum $dump_file`;
my $value = (split(" ",$md5sum))[0];
print $fh $value;
close $fh;
compare($a,$b);
# question: what is in $a / $b and what does compare do ?
}
现在比较$ a和$ b并返回该结果。 假设$ a / $ b包含一些有用的东西,那么在我看到更改的until块或CHECK块中没有任何内容,因此比较将保持返回相同的结果(假设"比较"比较而不是改变任何东西,如果确实如此,这将是一个糟糕的命名)。
所以在until块中,做一些事情来影响CHECK,否则你会被困在一个循环中。
答案 2 :(得分:0)
您应该始终在本地标识符中使用小写字符。大写字母保留用于包名称等全局标识符。在这种情况下,您无意中创建了CHECK
块
在运行的Perl程序的开头和结尾处执行五个特别命名的代码块。这些是
BEGIN
,UNITCHECK
,CHECK
,INIT
和END
块。这些代码块可以以sub为前缀,以提供子例程的外观(尽管这不被认为是好的样式)。应该注意的是,这些代码块并不真正作为命名子例程存在(尽管它们的外观)。实现这一目标的事实是,您可以在程序中拥有多个这些代码块,并且它们将在适当的时刻执行。因此,您无法按名称执行任何这些代码块。
因为“这些代码块并不真正作为命名子程序存在”你的程序在编译期间只会 调用CHECK
。这意味着将忽略对CHECK的显式调用,$status
永远不会更改
将您的子程序更改为check
,一切都很好
答案 3 :(得分:0)
问题在于:
until ($status == 0 ) {
print "\n\tfiles are now Ok. Exiting..";
print "\n\t";
}
循环中没有任何地方可以更改$status
。
"do CHECK;"
不属于循环。
将通过CHECK
子的返回值的名称来评估文件 如果它实际上已经调用了那个子 它不会,因为它实际上不是一个子程序。
until
的另一种形式是:
do {
CHECK; # doesn't work as this is a special name
} until $status == 0;
print "\n\tfiles are now Ok. Exiting..";
print "\n\t";
这仍然是个问题,因为CHECK
是一个块的特殊名称,只能在CHECK时调用一次,实际上你无法调用。
另外CHECK
中的代码总是会有相同的结果,所以反复调用它没有意义,如果它第一次不起作用,仍会导致无限循环。
这是让你的代码对我有意义的第一步,也解决了上面指出的一些错误。
我还将$a
和$b
更改为$ref
和$new
,因为$a
和$b
是保留变量。
我通过使用Perl附带的模块改进了它,因此我不必检查open()
和close()
(autodie)的返回值,或者依赖约定特定平台(Digest::MD5和File::Spec::Functions)。
我假设您已加载File::Compare。
我从$status
子句中删除了check
的设置,以减少全局变量的使用。
#! /usr/bin/env perl
use strict;
use warnings;
use 5.10.1; # set minimum version which was released in 2009
use autodie;
use File::Spec::Functions qw' catfile catdir rootdir curdir ';
use Digest::MD5;
use File::Compare qw' compare ';
# should be // not ||, but it will work if your dir isn't named "0" or ""
my $basedir = $ENV{HOME} || catdir rootdir, qw' home vivek ';
# try the current directory if it doesn't exist
$basedir = curdir unless -d $basedir;
my $ref = catfile $basedir, 'generated_mdsum_reference.out';
my $new = catfile $basedir, 'generated_mdsum_new.out';
my $dumpfile = catfile $basedir, 'file_dump.dmp';
# forward declare so that we can put them at the end
sub md5_hex_file;
sub md5_sum;
sub check;
#-------------------------------------------------------
if ( compare($new, $ref) != 0 ){
if ( check($dumpfile,$new) == 0 ){
print "\n\tfiles are now Ok. Exiting..\n";
} else {
local $| = 1; # make sure the output is flushed to STDOUT
print "\n\tfiles are NOT OK. Exiting..\n";
exit 1;
}
}
#-------------------------------------------------------
# helper subroutines
sub md5_hex_file {
my ($filename) = @_;
# let Digest::MD5 read the file for us
my $ctx = Digest::MD5->new;
{ # limit scope of $fh
open my $fh, '<', $filename;
binmode $fh;
$ctx->addfile( $fh );
close $fh;
}
$ctx->hexdigest;
}
# no longer necessary
sub md5_sum {
my ($filename) = @_;
# `md5sum -b $filename`
md5_hex_file($filename) . " $filename\n";
}
sub check {
my ( $infile, $outfile ) = @_
print "\n" x 3, "\tGenerating MD5SUM ....\n";
my $md5_hex = md5_hex_file $infile;
print "\n" x 2, "Checksum: $md5_hex.\n";
# Put checksum in file
{
open my $out_fh, '>', $outfile;
print {$out_fh} $md5_hex;
close $out_fh;
}
my $status = compare $new, $ref;
return $status if $status == 0;
# add a newline and hope that fixes it
{
open my $out_fh, '>>', $outfile;
print {$out_fh} "\n";
close $out_fh;
}
return compare $new, $ref;
}
我觉得你真的可以使用这些“单行”
$ perl -Mautodie -MDigest::MD5 -e \
'open $fh, q[<], shift;
print Digest::MD5->new->addfile($fh)->hexdigest' \
file_dump.dmp > generated_mdsum_new.out
$ perl -MFile::Compare -e \
'if ( compare(shift(),shift()) == 0 ){
print qq[They match\n]
} else {
print qq[They don\'t match\n]
}' \
generated_mdsum_new.out generated_mdsum_reference.out