找不到错误“全局符号@xx需要显式包名”

时间:2015-04-26 05:39:34

标签: perl

我已经检查了可能已经有答案的问题,但没有一个问题有帮助。

这是我的Unix编程学期项目。我创建了一个脚本,用于将HTML文件与网站中的其他文件进行比较。

该脚本完美按预期工作,直到我尝试实现第二个网站,因此我删除了第二个网站的添加代码,现在我收到了错误

Global symbol "@master" requires explicit package name
Global symbol "@child" requires explicit package name

csite_md5子程序中。我已多次浏览代码,无法看到问题。

我正在寻找另一组眼睛,看看我是否只是缺少一些简单的东西,通常就是这种情况。

我也是Perl的新手,因为这是我第一次使用这种语言。

#!/usr/bin/perl

use strict;
use warnings;

use Digest::MD5 qw(md5_hex);
use File::Basename;

# Path to the c-site download root directory
my $csite_dir = '/root/websites/c-site/wget/';

opendir my $dh, $csite_dir or die $!;

# Finds the sub directories c-site_'date +%F' where the c-site download is located
my @wget_subdir_csite = sort grep /^[^.]/, readdir $dh;

# Creates the absolute path to the c-site download
my $csite_master_dir = "$csite_dir$wget_subdir_csite[0]/dayzunderground.webs.com";
my $csite_child_dir = "$csite_dir$wget_subdir_csite[1]/dayzunderground.webs.com";

# Call to subroutine to append the .html file name to the absolute path
my @master_csite = &gethtml_master_csite($csite_master_dir);
my @child_csite = &gethtml_child_csite($csite_child_dir);

&csite_md5(\@master_csite, \@child_csite);

sub gethtml_master_csite{

    my ($master_path) = @_;
    opendir (DIR, $master_path) or die $!;

    # Ends with .html and is a file
    my @html_master = sort grep {m/\.html$/i && -f "$master_path/$_"} readdir(DIR);

    my @files_master = ("$master_path/$html_master[0]","$master_path/$html_master[1]","$master_path/$html_master[2]","$master_path/$html_master[3]");

    return @files_master
}
sub gethtml_child_csite{

    my ($child_path) = @_;
    opendir (DIR, $child_path) or die $!;

    # Ends with .html and is a file
    my @html_child = sort grep {m/\.html$/i && -f "$child_path/$_"} readdir(DIR);

    my @files_child = ("$child_path/$html_child[0]","$child_path/$html_child[1]","$child_path/$html_child[2]","$child_path/$html_child[3]");

    return @files_child
}

sub csite_md5{

    my ($master, $child) = @_;

    if(&md5sum($master[0]) ne &md5sum($child[0])){

        my $filename = basename($master[0]);
        system("diff -u -d -t --width=100 $master[0] $child[0] > ~/websites/c-site/diff/c-site-$filename-`date +%F`");

        #print "1"
    }
    if(&md5sum($master[1]) ne &md5sum($child[1])){

        my $filename2 = basename($master[1]);
        system("diff -u -d -t --width=100 $master[1] $child[1] > ~/websites/c-site/diff/c-site-$filename2-`date +%F`");

        #print "2"
    }
    if(&md5sum($master[2]) ne &md5sum($child[2])){

        my $filename3 = basename($master[2]);
        system("diff -u -d -t --width=100 $master[2] $child[2] > ~/websites/c-site/diff/c-site-$filename3-`date +%F`");
        #print "3"
    }
    if(&md5sum($master[3]) ne &md5sum($child[3])){

        my $filename4 = basename($master[3]);
        system("diff -u -d -t --width=100 $master[3] $child[3] > ~/websites/c-site/diff/c-site-$filename4-`date +%F`");

        #print "4"
    }
}

sub md5sum{
    my $file = shift;
    my $digest = "";
    eval{
        open(FILE, $file) or die "Can't find file $file\n";
        my $ctx = Digest::MD5->new;
        $ctx->addfile(*FILE);
        $digest = $ctx->hexdigest;
        close(FILE);
    };
    if($@){
        print $@;
        return "";
    }
    return $digest
}

2 个答案:

答案 0 :(得分:4)

$master$child是数组引用;像$master->[0]一样使用它们。 $master[0]使用数组@master,这是一个完全独立的变量。

答案 1 :(得分:1)

我认为通过您的计划并指出一些不太理想的做法可能有所帮助

  • 调用Perl子例程时,不应使用&符号&。这是Perl 4所要求的,它在大约22年前被取代

  • 最好使用File::Spec模块来处理文件路径,以处理多路径分隔符和可移植性等情况。 File::Spec也将执行File::BaseName

  • 的工作
  • 不必使用shell来创建日期字符串。使用Time::Piece模块,localtime->ymd生成与date +%F相同的字符串

  • 在适当情况下使用map而不是编写多个相同的作业更整洁,更简洁

  • gethtml_master_csitegethtml_child_csite子例程是相同的,只是它们在内部使用不同的变量名。它们可以由单个gethtml_csite子例程

  • 替换
  • 您应该使用 lexical 文件和目录句柄,就像使用第一个opendir一样。您还应该使用open的三参数形式(以打开模式作为第二个参数)

  • 如果open失败,那么您应该在$!字符串中包含变量die,以便您知道 失败的原因。此外,如果您使用换行符结束字符串,则Perl不会在打印时将源文件和行号附加到字符串

  • 如您所读,csite_md5尝试使用不存在的数组@master@child。您有数组引用 $master$child。此外,子程序适用于循环结构,而不是明确地编写四个比较

  • md5sumeval调用失败时,您使用了die来抓住open。明确地检查这个

  • 更好
  • 从子例程返回 false 值的标准方法是裸return。如果您return '',那么它将在列表上下文中评估为 true

有了这些chnages,你的代码就像这样。请问您是否有任何问题需要了解它。请注意,我无法测试它,但它确实编译了

#!/usr/bin/perl

use strict;
use warnings;

use Digest::MD5 qw(md5_hex);
use File::Spec::Functions qw/ catdir catfile splitpath /;
use Time::Piece 'localtime';

my $csite_dir = '/root/websites/c-site/wget/';

opendir my $dh, $csite_dir or die qq{Unable to open "$csite_dir": $!};

my @wget_subdir_csite = sort grep /^[^.]/, readdir $dh;

my ($csite_master_dir, $csite_child_dir) = map
        catdir($csite_dir, $_, 'dayzunderground.webs.com'),
        @wget_subdir_csite[0,1];

my @master_csite = gethtml_csite($csite_master_dir);
my @child_csite  = gethtml_csite($csite_child_dir);

csite_md5(\@master_csite, \@child_csite);

sub gethtml_csite {

    my ($path) = @_;

    opendir my $dh, $path or die qq{Unable to open "$path": $!};
    my @files = sort grep { /\.html$/i and -f } map catfile($path, $_), readdir $dh;

    return @files;
}

sub csite_md5 {

    my ($master_list, $child_list) = @_;

    for my $i ( 0 .. $#$master_list ) {

        my ($master, $child) = ($master_list->[$i], $child_list->[$i]);

        if ( md5sum($master) ne md5sum($child) ) {
            my $filename = (splitpath($master))[-1]; # Returns (volume, path, file)
            my $date = localtime->ymd;
            system("diff -u -d -t --width=100 $master $child > ~/websites/c-site/diff/c-site-$filename-$date");
        }
    }
}

sub md5sum {

    my ($file) = @_;
    my $digest = "";

    open my $fh, '<', $file or do {
        warn qq{Can't open file "$file": $!};   # '
        return;
    };

    my $ctx = Digest::MD5->new;
    $ctx->addfile($fh);

    return $ctx->hexdigest;
}