perl storing hash in %ENV - perl

I want to (ab-)use the global %ENV to store a hash. This seems to work differently for %ENV than for ordinary hashes. in the program below, the $ENV{myhash} still contains 'myhash' => 'HASH(0x7ffad8807380)' and the %ahash is still around. is it possible to convert the hex address back to point at its location, instead of just containing the string? I guess I could serialize and unserialize the hash instead. what is the right way to do this?
#!/usr/bin/perl -w
use common::sense;
use Data::Dumper;
my %QENV = ( nohash => 'noh' );
my %ahash= ( hv1 => 'htext1', hv2 => 'htext2' );
$QENV{'myhash'} = \%ahash;
print "works: ". Dumper(\%QENV)."\n\n\n";
$ENV{'myhash'} = \%ahash;
print "fails: ". Dumper(\%ENV)."\n";

%ENV is a magical hash. It reflects the process's environment. Reading from it reads from the environment, and writing to it changes the environment.
If you can guarantee the referenced variable is still alive (by it still being in scope or by it having its REFCNT increased), you can indeed create a reference to it from the address.
use strict;
use warnings;
use Data::Dumper;
use Inline C => <<'__EOS__';
SV* _newRV(IV iv) {
return newRV((SV*)iv);
}
__EOS__
my %hash = ( a => 1, b => 2 );
my $ref = \%hash;
my $ref_string = "$ref";
my $addr = hex( ( $ref_string =~ /\((.*)\)/ )[0] );
my $ref2 = _newRV($addr);
print(Dumper($ref2));
I have no idea why you'd want to do this. It would not permit another process to access the data since one process can't access the memory of another.

You seem to want to share data. Here's an example I put out there often that shows how to store data in a JSON file, then retrieve it. JSON is cross-language, so the data can be used by many programming languages, not just Perl. Although this example is within a single script, imagine it being two different Perl applications:
use warnings;
use strict;
use JSON;
my $file = 'data.json';
my %h = (
foo => 'bar',
raz => {
ABC => 123,
XYZ => [4, 5, 6],
}
);
my $json = encode_json \%h;
# write the JSON to a file, and close it
open my $fh, '>', $file or die $!;
print $fh $json;
close $fh or die $!;
# open the JSON file, and read it
open my $json_file, '<', $file or die $!;
my $read_json;
{
local $/;
$read_json = <$json_file>;
}
my $perl_hash = decode_json $read_json;

Related

How can I store simple hash in perl using data dumper

%hash = ('abc' => 123, 'def' => [4,5,6]);
how can I store above hash in file using data dumper in Perl
Files can only contain sequences of bytes, so you need to convert the data structure into a sequence of bytes somehow. This process is called serialization.
The possibilities available to you are endless, but a few are worth mentioning:
JSON is a very common choice.
YAML is more flexible.
Storable is specifically made for Perl data structures.
There is also Data::Dumper, as you say.
use Data::Dumper qw( );
sub serialize {
my ($x) = #_;
local $Data::Dumper::Purity = 1; # Required for some data structures.
local $Data::Dumper::Useqq = 1; # Optional. Limits output to ASCII.
local $Data::Dumper::Sortkeys = 1; # Optional. Makes revision control easier.
return Data::Dumper->Dump([$x], ["x"]);
}
print($fh serialize($x));
Data::Dumper isn't a particularly good choice, since there's no existing module to safely deserialize the structure in Perl[1], and there's even less support outside of Perl.
sub deserialize {
my ($s) = #_;
my $x;
eval($s); # XXX Unsafe!
die($#) if $#;
return $x;
}
If you're ok with limiting yourself to data structure JSON can serialize (by setting Purity to 0), then you could use Data::Undump to safely deserialize. But then why not just use JSON?!
use Data::Dumper
open (FL, ">", "file.txt") or die "Cant open file $! ";
print FL Dumper \%hash;
close FL;
"how can I store above hash in file using data dumper in Perl"
Store it as JSON so it can be read back by (almost) anything, using Data::Dumper configured to print JSON.
use strict;
use warnings;
use Data::Dumper;
local $Data::Dumper::Pair = ' : ';
local $Data::Dumper::Quotekeys = 1;
local $Data::Dumper::Useqq = 1;
local $Data::Dumper::Terse = 1;
my %hash = ('abc' => 123, 'def' => [4,5,6]);
open my $file, '>', 'foo.json' or die $!;
print $file Dumper \%hash;
Output:
$ cat foo.json
{
"def" : [
4,
5,
6
],
"abc" : 123
}
(Note: I would of course rather use a dedicated JSON-handling module for this, but you asked ....)

Extracting and storing the the values in key value pair from a text in file in perl

I have a text file like which contains information like this:
name=A
class=B
RollNo=C
I want to extract the values in perl script
key(name) = value(A)
key(class) = value(B)
key(RollNo) = value(C)
the keys should be exported as the variables which will have values. Whenever we type
print $name
the output should be 'A'
I have tried:
open my $fh, '<', $file_name
or die "Could not open sample.txt: $!";
my #lines = <$fh>;
my %hash;
while (<#lines>) {
chomp;
my ($key, $value) = split /=/;
next unless defined $value;
$hash{$key} = $value;
}
print %hash;
Your code looks pretty good and most of what you've done so far works.
At the end, you run print %hash and that doesn't give you what you expect. That will "unroll" the keys and values from the hash into a list and print that list. So you get all of the keys and values printed out.
If you just want one value (for example, the value associated with the "name" key), then just print that.
print $hash{name};
Is that what you were looking for?
You could try using one of the configuration modules that are available. Config::Tiny seems to fit your data:
use strict;
use warnings;
use Data::Dumper;
use Config::Tiny;
my $Config = Config::Tiny->new;
$Config = Config::Tiny->read( 'a.txt' ); # your text file name goes here
print $Config->{_}{name}; # print the name value
print Dumper $Config; # print all the values in perl variable format
You can store data in hash and can retrieve from their.
use strict;
use warnings;
use Data::Dumper;
my %hash = (
name => 'A',
class => 'B',
RollNo => 'C'
);
print Dumper(\%hash);
print $hash{'name'};

Including a perl file that is generated in current file

I am working on a perl script that successfully generates output files containing hashes. I want to use those hashes in my file. Is it possible to include a file that is generated in that file or will I have to create another file?
Technically, it might be cleaner to start a new .pl file that uses those hashes, but I would like to keep everything in a single script if possible. Is it even possible to do so?
Edit: I'm just unsure if I can "circle" it back around so I can use those hashes in my file because the hashes are generated on a weekly basis. I don't want my file to mistakenly reach out for last week's hashes instead of the newly generated ones. I have not yet wrote my script in a manner to classify each week's generated hashes.
In summary, here is what my file does. It extracts a table from another file. removes columns and rows that are not needed. Once left with the only two columns needed, it takes them and puts them into a hash. One column being the key and the other being the value. For this reason, I've found Data::Dumper to be the best option for my hashes. I'm intermediate in Perl and this is a script I'm putting together for an internship.
Here is an example how you can save a hash as JSON to a file and later read back the JSON to a perl hash. This example is using JSON::XS:
use strict;
use warnings;
use Data::Dumper;
use JSON::XS;
{
my %h = (a => 1, b => 2);
my $str = encode_json( \%h );
my $fn = 'test.json';
save_json( $fn, \%h );
my $h2 = read_json( $fn );
print Dumper( $h2 );
}
sub read_json {
my ( $fn ) = #_;
open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
my $str = do { local $/; <$fh> };
close $fh;
my $h = decode_json $str;
return $h;
}
sub save_json {
my ( $fn, $hash ) = #_;
my $str = encode_json( $hash );
open ( my $fh, '>', $fn ) or die "Could not open file '$fn': $!";
print $fh $str;
close $fh;
}
Output:
$VAR1 = {
'a' => 1,
'b' => 2
};
Some alternatives to JSON are YAML and Storable.

Using Storable to store hash and use it in another script

I am storing a hash in a script like so (part of code left out):
use strict;
use warnings;
use utf8;
use Storable qw(nstore_fd);
open( my $fh, ">", 'hash.hash');
my $hash_ref = \%hash;
nstore_fd($hash_ref, $fh);
close $fh;
Which creates a file hash.hash. In another file, then, I try to 'import' the hash and read its values to be used (e.g. looping the hash, reading values, checking existence ...).
I tried something simple, i.e. read the hash, dereference and read its keys, and print those out. However I get the error Not a HASH reference at CreateSql.pl line 12. It is a scalar. But I don't see why. The documentation of the module states that a reference is returned.
To retrieve data stored to disk, use retrieve with a file name. The
objects stored into that file are recreated into memory for you, and a
reference to the root object is returned.
So what did I do wrong, and how do I get access to the stored hash?
use strict;
use warnings;
use utf8;
use Data::Dumper;
use Storable qw(retrieve);
my ($hash_path) = #ARGV;
my $hash_ref = retrieve($hash_path);
my #keys = keys % { $hash_ref }; # throws error
print Dumper(\#keys);
You really must show the code that has given you the problems that you describe, otherwise it becomes very hard to help you. The code in your question doesn't compile. If you want to make changes to the program before you publish it, the test it again to make sure that it at least compiles, and also display the problems you're reporting
The main problem is that you are writing binary data to a file opened as text. If you change open( my $fh, ">", 'hash.hash') to open( my $fh, ">:raw", 'hash.hash') then everything should work
This variant of your own code correctly stores and retrieves some sample data
use strict;
use warnings 'all';
use Storable qw/ nstore_fd retrieve /;
use constant STORAGE => 'hash.hash';
my %hash = ( a => 'b', c => 'd' );
{
open my $fh, '>:raw', STORAGE or die $!;
nstore_fd \%hash, $fh;
}
my $hash_ref = retrieve STORAGE;
use Data::Dump;
dd $hash_ref;
my #keys = keys % { $hash_ref }; # throws error
dd \#keys;
output
{ a => "b", c => "d" }
["a", "c"]
However, you've made some strange choices. There's no need to use an nstore function to store the data in "network order", and you could have avoided the problem altogether if you had let the module open the file itself
Here's a variant that just uses store and retrieve. The output is identical to that of the code above
use strict;
use warnings 'all';
use Storable qw/ store retrieve /;
use constant STORAGE => 'hash.hash';
my %hash = ( a => 'b', c => 'd' );
store \%hash, STORAGE;
my $hash_ref = retrieve STORAGE;
use Data::Dump;
dd $hash_ref;
my #keys = keys % { $hash_ref }; # throws error
dd \#keys;

How to read back a file written using Data::Dumper (but not with the default VAR naming)?

I have written a hash structure into a file using
print FILE Data::Dumper->Dump([$x], [ qw(*x) ]);
How do I read this back from file? If I use eval as shown in the following snippet, all I get is $VAR1 = undef;
local $/; $hash_ref = eval <FILE>;
You can use the core module Storable to do this type of task.
use Storable;
store \%table, 'file';
$hashref = retrieve('file');
If those two statements are in the same file, then you can't do it that way unless you close the file handle and reopen the same file for reading. You could do something fancy like opening it with mode +> and then using seek to get back to the beginning before you read again, but why bother, especially since you already have a variable in the same program that contains the same data.
So I assume you are dumping the data from one program and reading it again in another. The problem with using Data::Dumper->Dump([$x], ['*x']) is that it will dereference $x and invent a variable of the appropriate type with the given name. So if $x is a hash reference it will name the variable %x, if it is an array reference then it will be #x etc.
It is far better to remove the star and just write Data::Dumper->Dump([$x], ['x']), which will avoid the dereferencing and name the variable $x.
To read the file back in you should just use do. Like this
use strict;
use warnings;
use Data::Dumper;
my $x = {
a => 1,
b => 2,
};
open my $fh, '>', 'dumper.txt' or die $!;
print $fh Data::Dumper->Dump([$x], ['x']);
close $fh;
my $data = do 'dumper.txt';
If you are constrained to using the form of Data::Dumper call that you show, then you must provide a variable of the appropriate type, like this
use strict;
use warnings;
use Data::Dumper;
my $x = {
a => 1,
b => 2,
};
open my $fh, '>', 'dumper.txt' or die $!;
print $fh Data::Dumper->Dump([$x], ['*x']);
close $fh;
my %data = do 'dumper.txt';
Note that, although the Data::Dumper output file refers to a variable %x, the file is run as a separate Perl program and there is no %x in the program that executes the do.
I tried several ways to export an existing hash. The only way I found that works is to create a new var that is a pointer to the existing hash.
Then Borodin's answer works well.
use strict;
use warnings;
use Data::Dumper;
my %x = (
a => 1,
b => 2,
);
my $x = \%x; # <<< Added so $x is a reference to %x.
open my $fh, '>', 'dumper.txt' or die $!;
print $fh Data::Dumper->Dump([$x], ['*x']);
close $fh;
my %data = do 'dumper.txt';