#! /usr/bin/perl
use strict;
use warnings;
use File::stat;
my $file_name = 0;
my $info = 0;
my $ret_mode = 0;
my $size;
my $last_mod;
my @array_file;
my $index = 0;
my @array_mode;
my @array_size;
my @array_last_mod;
foreach(@ARGV){
$file_name = $_;
$info = stat($file_name);
$size = $info->size;
$last_mod = scalar(localtime($info->mtime));
$ret_mode = $info->mode;
$ret_mode = $ret_mode & 0777;
$array_file[$index] = ($file_name);
$array_mode[$index] = ($ret_mode);
$array_size[$index] = ($size);
$array_last_mod[$index] = ($last_mod);
$ret_mode = 0;
$index++;
}
my @array_arrays = (@array_file, @array_mode, @array_size, @array_last_mod);
my $array_ref = \@array_arrays;
my $i = 0;
for(@$array_ref){
print "@$array_ref[$i]\n";
$i++;
}
我创建了一个数组数组,我想从创建的数组数组中打印文件名,mmode,大小和最后访问时间。它没有打印任何值,
for(@$array_ref){
print "@$array_ref[$i]\n";
$i++;
}
答案 0 :(得分:5)
my @array_arrays = (@array_file, @array_mode, @array_size, @array_last_mod);
此语句不会创建数组数组。相反,它将各种数组展平为一个大的平面列表,然后将其分配给@array_arrays
。您想要分配数组引用。使用引用运算符\
获取那些:
my @array_arrays = (\@array_file, \@array_mode, \@array_size, \@array_last_mod);
或使用快捷方式
my @array_arrays = \(@array_file, @array_mode, @array_size, @array_last_mod);
即使这样,你的上一个foreach
- 循环也是错误的。你可能意味着
for my $i (0 .. $#{ $array_arrays[0] }) {
for my $aref (@array_arrays) {
print $aref->[$i], "\n";
}
}
或类似的东西。
您的代码风格可以改进。
请不要在顶部声明所有变量。尽可能在最严格的范围内声明它们。尝试在初始化时声明它们,例如
for my $file_name (@ARGV) {
my $info = stat($file_name);
my size = $info->size;
...
}
不要在数组名称前添加array_
前缀。 @
sigil和/或[...]
运算符下标表明这些是数组。
$ret_mode & 0777
- 结果应为$ret_mode
本身:0777
为0b111111111
。即除去最后9位之外的所有内容 - 如果左边有更多内容你就不在乎了。
$last_mod = scalar(localtime($info->mtime));
- 由于标量赋值,localtime
已在标量上下文中执行。无需明确说明。
my $index = 0; ... for (...) { $array[$index] = ...; $index++ }
。请不要。只需使用push
:for (...) { push @array, ... }
即可。除非必须,否则不要自己维护索引。
$ret_mode = 0;
为什么?无论如何,你在下一次迭代中分配一个新值。请注意,您应该在循环中声明这些变量(请参阅我关于紧密范围的观点),这将在每次迭代中创建一个新变量,这使得它更加无用。
my $array_ref = \@array_arrays; .. @$array_ref[$i]
。这有点倒退吗? $array_arrays[$i]
也可以正常运作。请注意,在你的推理中,@
可能是错误的印记。你的意思是$$array_ref[$i]
。
答案 1 :(得分:3)
让我们尝试一些不同的东西。
首先,对于引用的数组和哈希,使用->
有一个很好的语法。在这里,我将创造一系列人。我将制作包含所有该人信息的%person
哈希:
my %person;
my $person{NAME} = "Bob";
my $person{JOB} = "Programmer";
my $person{PHONE} = "555-1234";
现在,我将把它放入一个数组中:
my @array
my $array[0] = \%person;
我可以用这种方式引用数组中的人:
print ${$array[0]}{NAME} . "\n"; #Prints Bob
print ${$array[0]}{JOB} . "\n"; #Prints Porgrammer
但是,Perl为我提供了一个很好的干净方法:
print $array[0]->{NAME} . "\n"; #Prints Bob
print $array[0]->{JOB} . "\n"; #Prints Progammer
事实上,我可以一起跳过哈希。我在这里将Jill添加到我的数组中:
$array[1]->{NAME} = "Jill";
$array[1]->{JOB} = "DBA";
$array[1]->{PHONE} = "555-5555";
您可以看到这是一种使用引用的简单方法。它更容易看到发生了什么并占用更少的代码。
您可以像这样引用一个数组数组:
$myarray[1]->[3] = 42;
或者有一个存储数组的哈希。在这个时代,谁只有一个电话号码?:
$person[1]->{PHONE}->[0] = "555-4567";
$person[1]->{PHONE}->[1] = "555-4444";
或者,为了使它更复杂,我们可以得到一个数组哈希的哈希值:
$person[1]->{PHONE}->{CELL}->[0] = "555-1111";
$person[1]->{PHONE}->{CELL}->[1] = "555-2222";
$person[1]->{PHONE}->{HOME}->[0] = "555-3333";
$person[1]->{PHONE}->{JOB}->[0] = "555-4444";
$person[1]->{PHONE}->{JOB}->[1] = "555-5555";
使用这种语法确实有助于清理大量代码。您不必将信息存储到单独的结构中,然后仅用于引用。相反,您可以根据需要简单地设置结构,而无需中间步骤。
现在问题 :您正在尝试将一堆有关文件的信息存储到一系列数组中。您希望$array_mode[1]
与$array_file[1]
一致,您必须保持所有这些数组同步。这是一种痛苦,而且很复杂。
使用引用的整个目的是消除对多个变量的这种需求。如果您要使用引用,为什么不将整个文件结构存储到单个数组中。
你真正想要的是一组哈希引用。并且,该哈希引用将根据您的文件属性进行键控。以下是使用哈希引用数组重构的代码。我甚至懒得检查剩下的部分。例如,我不确定你的本地时间是如何工作的:
use strict;
use warnings;
use feature qw(say);
use File::stat;
my @files;
for my $file ( @ARGV ) {
my $info = stat( $file );
my $file = {}; #This will be a reference to a hash
$file->{NAME} = $file;
$file->{SIZE} = $info->size;
$file->{RET_MODE} = $info->mode & 0777;
$file->{LAST_MOD} = localtime $info->mtime; #Does this work?
push @files, $file #Pushes the hash reference onto the array
}
这样更短更清洁。另外,您知道$files[0]->{NAME}
与$files[1]->{SIZE}
一致,如果您从数组中删除$files[0]
,或将其传输到另一个变量,则该文件的所有属性都会一起使用。
以下是打印出来的方式:
for my $file ( @files ) {
say "File Name: " . $file->{NAME};
say "File Size: " . $file->{SIZE};
say "Last Modified: " . $file->{LAST_MOD};
say "File Mode: " . $file->{RET_MODE};
}
简单易行。
但是,我认为你真正想要的是哈希的哈希。让您的文件名成为主哈希的关键,让{SIZE}
,{LAST_MOD}
和{RET_MODE}
成为子哈希的关键:
my %files = {}; #This is a hash of hashes
for my $file_name ( @ARGV ) {
my $info = stat( $file );
$files{$file_name}->{SIZE} = $info->size;
$files{$file_name}->{RET_MODE} = $info->mode & 0777;
$files{$file_name}->{LAST_MOD} = localtime $info->mtime; #Does this work?
}
现在,如果有人问,“上次修改时间foo.txt
?”,您可以说:
say "File 'foo.txt' was last modified on " . $file{foo.txt}->{LAST_MOD};
打印出整个结构:
for my $file_name ( sort keys %files ) {
say "File: $file_name";
for my attribute ( sort keys %{ $file_name } ) {
say " $attribute: " . $files{$file_name}->{$attribute};
}
}
下一步是了解Object Oriented Perl!面向对象的Perl使用这些类型的引用,但会大大简化这些引用的处理,因此您可以减少编程错误。