2013-08-18 3 views
1
#! /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, размера и время последнего доступа из массива массивов, созданных. Его не печать любых значений с,Как напечатать массив массивов в Perl - ссылочный переменной

for(@$array_ref){ 
    print "@$array_ref[$i]\n"; 
    $i++; 
} 
+1

Отъезд perlLOL - официальные документы в [списки списков в perl] (http://perldoc.perl.org/perllol.html) –

ответ

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 -loop неправильно. Вероятно, вы имели в виду

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_. Сигила и/или подписка на @ с оператором [...] дают понять, что это массивы.

  • $ret_mode & 0777 - Результат должен быть $ret_mode сам: 0777 is 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] будет работать так же хорошо. Обратите внимание, что в вашей defeferencing, @, вероятно, является неправильной сигилой. Вы имели в виду $$array_ref[$i].

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 

Фактически, я мог бы пропустить хэш все вместе. Здесь я добавляю Джил к моему массиву:

$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 использует эти типы ссылок, но значительно упростит обработку этих ссылок, поэтому вы будете делать меньше ошибок программирования.