在perl上的rysnc,直到循环永不中断

时间:2015-08-05 01:27:09

标签: perl

我在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”

请帮帮我们。

4 个答案:

答案 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

perldoc perlmod说这个

  

在运行的Perl程序的开头和结尾处执行五个特别命名的代码块。这些是BEGINUNITCHECKCHECKINITEND块。

     

这些代码块可以以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

perldoc perlmod说这个

  

在运行的Perl程序的开头和结尾处执行五个特别命名的代码块。这些是BEGINUNITCHECKCHECKINITEND块。

     

这些代码块可以以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::MD5File::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