JaeDre619 has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I am trying to learn how to dereference hashref/arrayrefs. So far I have managed to get my test results I want, but having to write (2) different scripts for it.
They are basically the same except for the iteration of the values. I need some help constructing a condition to print the keys I need.

I have a couple of data structures (see below) which is from an xml file and is handled using XML::Simple using ForceArray =>1.

Here is the data structure from dumper, I am working with:

$VAR1 = { 'recursive' => 'no', 'version' => '0.20.202.1.1101050227', 'time' => '2011-10-26T00:21:06+0000', 'filter' => '.*', 'path' => '/work/eng/feeds/customer_care', 'directory' => [ { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwxr-xr-x', 'path' => '/work/eng/feeds/customer_car +e', 'accesstime' => '1970-01-01T00:00:00+00 +00', 'modified' => '2011-10-25T23:54:17+0000 +' }, { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwx------', 'path' => '/work/eng/feeds/customer_car +e/abc', 'accesstime' => '1970-01-01T00:00:00+00 +00', 'modified' => '2011-10-25T17:12:56+0000 +' }, { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwx------', 'path' => '/work/eng/feeds/customer_car +e/def', 'accesstime' => '1970-01-01T00:00:00+00 +00', 'modified' => '2011-10-25T21:05:50+0000 +' }, { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwx------', 'path' => '/work/eng/feeds/customer_car +e/test', 'accesstime' => '1970-01-01T00:00:00+00 +00', 'modified' => '2011-10-25T21:28:14+0000 +' } ], 'exclude' => '' };

Here is the code part to extract the directories:

my $lsResults = $cmd->ls("$chkdir"); #$chkdir = "/work/eng/feeds/custo +mer_care" #print Dumper($lsResults); for my $dirnm ( @{$lsResults->{directory}} ) { print "Directory: " . $dirnm->{path} . "\n"; }

Results:

Directory: /work/eng/feeds/customer_care Directory: /work/eng/feeds/customer_care/abc Directory: /work/eng/feeds/customer_care/def Directory: /work/eng/feeds/customer_care/test

The results are fine, until I list the sub-directory that happens to have files: $chdkir="/work/eng/feeds/customer_care/test"

Which in the case the test directory has files and size information that I want to list, but can't due to this message:

Not an ARRAY reference at ./tst.pl

Here is the data dump with that new directory, that shows a file:

$VAR1 = { 'recursive' => 'no', 'version' => '0.20.202.1.1101050227', 'time' => '2011-10-26T00:30:02+0000', 'filter' => '.*', 'file' => { 'owner' => 'tst_act', 'replication' => '3', 'blocksize' => '134217728', 'permission' => '-rw-------', 'path' => '/work/eng/feeds/customer_care/test/ +q_data_20111023.dat', 'modified' => '2011-10-26T00:29:46+0000', 'size' => '379085', 'group' => 'eng', 'accesstime' => '2011-10-26T00:29:46+0000' }, 'path' => '/work/eng/feeds/customer_care/test', 'directory' => { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwx------', 'path' => '/work/eng/feeds/customer_care/ +test', 'accesstime' => '1970-01-01T00:00:00+0000 +', 'modified' => '2011-10-26T00:29:46+0000' }, 'exclude' => '' };

So, to get the file and sizes, I am using this in a separate perl script

my $lsResults = $cmd->ls("$chkdir"); #print Dumper($lsResults); for my $filenm ( @{$lsResults->{file}} ) { print "Filename: " . $filenm->{path} . "\n"; print " Size: " . $filenm->{size} . "\n"; }

Results:

Filename: /work/eng/feeds/customer_care/test/q_data_20111023.dat Size: 379085

What I need help is combining these scripts, combining the logic where: whatever directory I pass in, if the directory has sub-directories, list the sub-directory. If the directory has filenames, list the directory, file, and size.

So, in this case if $chkdir="/work/eng/feeds/customer_care/test"

Expected Output:

Directory: /work/eng/feeds/customer_care/test Filename: /work/eng/feeds/customer_care/test/q_data_20111023.dat Size: 379085

Replies are listed 'Best First'.
Re: Setting up conditional check for printing out keys from array/hash ref
by GrandFather (Saint) on Oct 27, 2011 at 08:15 UTC

    There are a large number of ways to solve this problem and the best solutions probably involve recursion to deal with nested directories. However, you haven't asked for such a solution (yet) so here's a solution that uses Perl 5.10 (and later)'s switch statement:

    use strict; use warnings; use 5.010; my $lsResults1 = { 'recursive' => 'no', 'version' => '0.20.202.1.1101050227', 'time' => '2011-10-26T00:21:06+0000', 'filter' => '.*', 'path' => '/work/eng/feeds/customer_care', 'directory' => [ { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwxr-xr-x', 'path' => '/work/eng/feeds/customer_care', 'accesstime' => '1970-01-01T00:00:00+0000', 'modified' => '2011-10-25T23:54:17+0000' }, { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwx------', 'path' => '/work/eng/feeds/customer_care/abc', 'accesstime' => '1970-01-01T00:00:00+0000', 'modified' => '2011-10-25T17:12:56+0000' }, { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwx------', 'path' => '/work/eng/feeds/customer_care/def', 'accesstime' => '1970-01-01T00:00:00+0000', 'modified' => '2011-10-25T21:05:50+0000' }, { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwx------', 'path' => '/work/eng/feeds/customer_care/test', 'accesstime' => '1970-01-01T00:00:00+0000', 'modified' => '2011-10-25T21:28:14+0000' } ], 'exclude' => '' }; my $lsResults2 = { 'recursive' => 'no', 'version' => '0.20.202.1.1101050227', 'time' => '2011-10-26T00:30:02+0000', 'filter' => '.*', 'file' => { 'owner' => 'tst_act', 'replication' => '3', 'blocksize' => '134217728', 'permission' => '-rw-------', 'path' => '/work/eng/feeds/customer_care/test/q_data_20111 +023.dat', 'modified' => '2011-10-26T00:29:46+0000', 'size' => '379085', 'group' => 'eng', 'accesstime' => '2011-10-26T00:29:46+0000' }, 'path' => '/work/eng/feeds/customer_care/test', 'directory' => { 'owner' => 'tst_act', 'group' => 'eng', 'permission' => 'drwx------', 'path' => '/work/eng/feeds/customer_care/test', 'accesstime' => '1970-01-01T00:00:00+0000', 'modified' => '2011-10-26T00:29:46+0000' }, 'exclude' => '' }; for my $result ($lsResults1, $lsResults2) { for (keys %$result) { when ('file') { print "Filename: $result->{file}{path}\n"; print " Size: $result->{file}{size}\n"; } when ('directory') { given (ref $result->{directory}) { when ('ARRAY') { for my $entry (@{$result->{directory}}) { print "Directory: $entry->{path}\n"; } } when ('HASH') { print "Directory: $result->{directory}{path}\n"; } } } } }

    Prints:

    Directory: /work/eng/feeds/customer_care Directory: /work/eng/feeds/customer_care/abc Directory: /work/eng/feeds/customer_care/def Directory: /work/eng/feeds/customer_care/test Filename: /work/eng/feeds/customer_care/test/q_data_20111023.dat Size: 379085 Directory: /work/eng/feeds/customer_care/test

    Notice the use of ref to determine what type of directory entry is being dealt with and the use of keys to work through the hash entries looking or the interesting stuff.

    True laziness is hard work
      thanks for your input. yes, the solution I was looking for was to make it recursive. unfortunately, the system I am using has perl version v5.8.6. What changes would I have to make with your solution?

        The sample solution I offered is not in itself recursive, although it could be the guts of a recursive solution.

        given/when is Perl's switch statement support which was introduced with 5.10. A switch statement is really just syntactic sugar for a set of related if statements so you can replace the when blocks with if blocks:

        for my $result ($lsResults1, $lsResults2) { for (keys %$result) { if ($_ eq 'file') { print "Filename: $result->{file}{path}\n"; print " Size: $result->{file}{size}\n"; } elsif ($_ eq 'directory') { my $value = ref $result->{directory}; if ($value eq 'ARRAY') { for my $entry (@{$result->{directory}}) { print "Directory: $entry->{path}\n"; } } elsif ($value eq 'HASH') { print "Directory: $result->{directory}{path}\n"; } } } }
        True laziness is hard work
Re: Setting up conditional check for printing out keys from array/hash ref
by choroba (Cardinal) on Oct 27, 2011 at 07:51 UTC
    You can use ref to tell you whether a reference points to a hash or an array.