Chetan
Chetan

Reputation: 1281

Read a perl hash file in perl

I have a file which has the data like below:

output.pl

{
    "A" => {
        "name" => "chetan",
        "age" => "28",
    },
    "B" => {
        "name" => "vivek",
        "age" => "31",
    },
};

Basically it is hash stored in other file.

How do I write a perl program to load this as a hash in a variable ?

I tried something like this:

use Data::Dumper;
use File::Slurp;

my %hash = read_file("output.pl");
print Dumper(keys(%hash));

But i see that it says odd number of elements assigned to hash.

Upvotes: 1

Views: 2210

Answers (3)

Hugh Barnard
Hugh Barnard

Reputation: 352

As above with Slurp, in a single line.

use File::Slurp ;

# no easy way to get current Mojolicious config, so this is a hack
my $config  = eval (read_file( '/etc/smsmap/sms_map.conf'));

Upvotes: 0

Grinnz
Grinnz

Reputation: 9231

You can load such data using the do function.

use strict;
use warnings;

my $file = './output.pl';
my $data = do $file;
# unfortunately 'do' error checking is very fragile
# there is no way to differentiate certain errors from the file returning false or undef
unless ($data) {
  die "couldn't parse $file: $@" if $@;
  die "couldn't do $file: $!" unless defined $data;
  die "$file did not return data";
}

This will of course run any arbitrary code within the file, but it is not generally a problem as long as the config file is not writable by anyone who can't also edit the script.

Some other options for config files that don't allow running arbitrary code would be JSON and Config::Tiny.

Make sure to use ./output.pl and not output.pl; without the leading ./ the do function will search @INC (which no longer contains the current directory in 5.26+) rather than just using the current directory.

If you want to load a file from the same directory as the current file rather than the current working directory (generally a more robust solution) see Dir::Self or Path::Tiny or similar, with an absolute path so that @INC is not searched.

use Dir::Self;
my $file = __DIR__ . '/output.pl';

use Path::Tiny;
my $file = path(__FILE__)->realpath->sibling('output.pl');

Upvotes: 2

Stefan Becker
Stefan Becker

Reputation: 5952

I see at least two problems in your code:

  1. you are trying to assign the contents of the file to the hash (instead of evaluating it)
  2. your file contains a hash ref, not a hash.

This is one alternative how to load and parse the file contents:

#!/usr/bin/perl
use warnings;
use strict;

use Data::Dumper;

# replacement for loading external file - not relevant for solution
my $content;
{
    local $/;
    $content = <DATA>;
}
#print "${content}\n";

my $hash = eval $content;
die "eval error: $@" if $@;
#print "${hash}\n";

print Dumper($hash);

exit 0;

__DATA__
{
    "A" => {
        "name" => "chetan",
        "age" => "28",
    },
    "B" => {
        "name" => "vivek",
        "age" => "31",
    },
};

Test Run:

$ perl dummy.pl
$VAR1 = {
          'A' => {
                   'name' => 'chetan',
                   'age' => '28'
                 },
          'B' => {
                   'name' => 'vivek',
                   'age' => '31'
                 }
        };

Upvotes: 2

Related Questions