1

I want to pass a hash reference as an argument from one perl script (script1.pl) to another perl script (script2.pl). This is how my code looks:

----------------------------script1.pl---------------------------------

#!/usr/bin/perl -w

use strict;
use warnings;

my %hash = (
'a'      => "Harsha",
'b'      => "Manager"
);

my $ref = \%hash;

system "perl script2.pl $ref";

----------------------------script2.pl---------------------------------

#!/usr/bin/perl -w

use strict;
use warnings;

my %hash = %{$ARGV[0]};

my $string = "a";

if (exists($hash{$string})){
    print "$string = $hash{$string}\n";
}

And this is the output error:

sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `perl script2.pl HASH(0x8fbed0)'

I can't figure out the right way to pass the reference.

4
  • 4
    Check for JSON or Storable with MIME::Base64 on CPAN. Commented Jul 17, 2015 at 9:42
  • Possible duplicates stackoverflow.com/questions/21325492/…, stackoverflow.com/questions/17082007/… Commented Jul 17, 2015 at 9:49
  • 1
    No need to use -w in shebang line when using use warnings. Commented Jul 17, 2015 at 10:11
  • Don't use system, use require instead. Commented Jul 17, 2015 at 10:52

4 Answers 4

9

A hash is an in memory data structure. Processes 'own' their own memory space, and other processes can't just access it. If you think about it, I'm sure you'll spot why quite quickly.

A hash reference is an address of that memory location. Even if the other process could 'understand' it, it still wouldn't be able to access the memory space.

What we're talking about here is actually quite a big concept - Inter Process Communication or IPC - so much so there's a whole chapter of the documentation about it, called perlipc.

The long and short of it is this - you can't do what you're trying to do. Sharing memory between processes is much more difficult than you imagine.

What you can do is transfer the data back and forth - not by reference, but the actual information contained.

I would suggest that for your example, the tool for the job is JSON, because then you can encode and decode your hash:

#!/usr/bin/perl -w

use strict;
use warnings;

use JSON;

my %hash = (
    'a' => "Harsha",
    'b' => "Manager"
);

my $json_string = to_json( \%hash );

print $json_string;

This gives:

{"b":"Manager","a":"Harsha"}

Then your can 'pass' your $json_string - either on the command line, although bear in mind that any spaces in it confuses @ARGV a bit if you're not careful - or via STDIN.

And then decode in your sub process:

use strict;
use warnings;

use JSON;

my $json_string = '{"b":"Manager","a":"Harsha"}';

my $json = from_json ( $json_string );

my $string = "a";

if (exists($json -> {$string} )){
    print "$string = ",$json -> {$string},"\n";
}

(You can make it more similar to your code by doing:

my $json = from_json ( $json_string );
my %hash = %$json;

Other options would be:

  • use Storable - either freezing and thawing ( memory) or storing and retrieving (disk)
  • use IPC::Open2 and send data on STDIN.

There's a variety of options really - have a look at perlipc. But it's not as simple a matter as 'just passing a reference' unfortunately.

Sign up to request clarification or add additional context in comments.

2 Comments

Nice explanation. You could also use FreezeThaw and pass the freezed string in ARGV..
Hadn't run into that, but have managed to accomplish similar with Storable. The major reason I didn't suggest that first is because I'm not entirely sure that a frozen scalar is that easy to pass on command line, because of binary content.
1

Use Storable to store data in first script and retrieve it from other.

firstscript.pl

store (\%hash, "/home/chankey/secondscript.$$") or die "could not store";
  system("perl", "secondscript.pl", $$) == 0 or die "error";

secondscript.pl

my $parentpid = shift;
my $ref = retrieve("/home/chankey/secondscript.$parentpid") or die "couldn't retrieve";
print Dumper $ref;

You've received the %hash in $ref. Now use it the way you want.

Comments

0

You can't pass a reference from one script to another - that reference only has meaning within the currently running instance of perl.

You would need to "serialise" the data in the first script, and then "deserialise" it in the second.

1 Comment

And how can I do this? Thanks.
-2

Your way of calling perl file is wrong. Just change the way of calling it and you are done.

Script1.pl
---------------------------------

#!/usr/bin/perl -w

use strict;
use warnings;

my %hash = (
    'a'      => "Harsha",
    'b'      => "Manager"
);

system("perl","script2.pl",%hash);

Use this %hash in another perl script as shown below.

Script2.pl
----------------------------------

#!/usr/bin/perl -w

use strict;
use warnings;

my %hash = @ARGV;

my $string = "a";

if (exists($hash{$string})){
    print "$string = $hash{$string}\n";
}

OutPut is

a = Harsha

2 Comments

Are you sure that works? It doesn't look like it should.
@Sobrique In this case it does work, because %hash is flattened in the system call, so it's really doing the equivalent of system("perl", "script2.pl", "a", "Harsha", "b", "Manager");. It won't work for nested data structures, objects, or a number of edge cases so I would serialize the data instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.