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

Hi Monks, I want to share a variable across multiple files. For this, I wrote one module, my_module.pm as below:
#!/usr/bin/perl package my_module; require Exporter; our @ISA = qw/Exporter/; our @EXPORT = qw/@my_var change_var/; our @my_var = (1..10); sub change_var{ @my_var = (20..30); } 1;
I used the module in 1.pl as below:
use my_module; print "@my_var\n"; # prints 1..10 change_var(); print "@my_var\n"; # prints 20..30 system("perl 2.pl"); # calling another script exit;
The other script 2.pl is as below:
use my_module; print "@my_var\n"; # prints 1..10 but expecting it to be 20..30
The changes made to the variable @my_var in 1.pl is not reflected in 2.pl. I want to make the variable @my_var global. Please let me know where I am wrong. Please suggest if I should take any other approach.

Replies are listed 'Best First'.
Re: Sharing a variable across multiple files
by Eily (Monsignor) on Aug 07, 2013 at 09:30 UTC

    The problem is that with system("perl 2.pl"); you call a new instance of perl, which has no shared memory with the one that calls it. Those are two different processes.

    What you probably want to do is do "2.pl", this way 2.pl will be run in the same context as 1.pl . Look do's documentation for information on that.

      Hi Eily, thank you for your suggestion. I did run the second script as do "2.pl" and that solved the problem :)
        Dear Monks, I gained some additional wisdom about the function 'do' which I would like to share.

        I used the do function in the first script to execute the second script in the same context (shared memory without creating another process by using system(..)). Though, I had to pass some arguments to the second script. do "2.pl $arg1" does not work.

        Finally I came to know that if we want to pass argument to the second script, we can exploit the idea that @ARGV will be visible to the second script. I achieved the goal as below:

        use my_module; print "@my_var\n"; # prints 1..10 change_var(); print "@my_var\n"; # prints 20..30 { # using local to supress @ARGV local @ARGV = ($arg1, $arg2...); # $arg1, $arg2... are the argumen +ts to be passed do "2.pl"; } exit;
        Now, in 2.pl I can get these arguments using shift.

        Regards,

        --Anupam

Re: Sharing a variable across multiple files
by kcott (Archbishop) on Aug 07, 2013 at 10:00 UTC

    G'day bihuboliya,

    "The changes made to the variable @my_var in 1.pl is not reflected in 2.pl. Please let me know where I am wrong."

    2.pl loads a fresh copy of my_module.pm with our @my_var = (1..10); — it knows nothing about changes made by 1.pl.

    "Please suggest if I should take any other approach."

    While it's good that you've provided a minimal example to demonstrate the problem, we'll need to know a bit more about what you're trying to achieve in order to advise on a better approach. Some possibilities are (in no particular order):

    • Pass the data directly to 2.pl. Getopt::Long may be useful for this.
    • open a pipe to 2.pl from 1.pl, e.g. open my $pipe, '|-', '2.pl'.
    • Pipe the data with a commandline call, e.g. 1.pl | 2.pl.
    • Use socket communication. perlipc has lots of information on this.
    • 1.pl stores the data to disk; 2.pl reads the data from disk: Storable can be used for this.

    [While Exporter was not the way to go here, your usage is generally not that good for any scenario. For future reference, see Selecting What to Export and What Not to Export.]

    -- Ken

      Hi Ken, thank you for the detailed answer :) I want to share quite a few number of variables across multiple files which act on those variables. Directly passing the variables would be little messy I suppose. You have directed me to various routes to get it done. I will explore them and revert back. Thanks for the time being. Regards, Anupam
Re: Sharing a variable across multiple files
by Loops (Curate) on Aug 07, 2013 at 10:51 UTC

    The answers above are more informative than this one will be. But your post inspired me to play with IPC::Shareable. It allows you to put variables into shared memory and access them from separate scripts. This is just a toy example and I don't have the experience required to recommend this as a solution. But it may be instructive.

    It consists of two scripts, adult.pl which will run child.pl in the background. After they're both running they each update a shared array.

    adult.pl:
    use IPC::Shareable; use Data::Dump qw(ddx); $| = 1; # Setup shared array reference "my_var" my $id = 'my_special_name'; my %options = (create => 'yes', exclusive => 0, mode => 0644, destroy +=> 'yes'); my $my_var; tie $my_var, 'IPC::Shareable', $id, { %options } or die "tie failed: $ +!\n"; $my_var = [0..10]; system('./child.pl &'); until ($my_var->[-1] == 999) { my $num = int(rand()*100); push @$my_var, $num; ddx [ @$my_var ]; sleep 2; }; print "Leaving adult.pl..\n";
    child.pl:
    use IPC::Shareable; use Data::Dump qw(ddx); $| = 1; my $id = 'my_special_name'; my %options = (create => 0, exclusive => 0, mode => 0644, destroy => 0 +); my $my_var; tie $my_var, 'IPC::Shareable', $id, { %options } or die "tie failed: $ +!\n"; for (0..3) { my $num = int(rand()*100); push @$my_var, $num; ddx [ @$my_var ]; sleep 2; } push @$my_var, 999; print "Leaving child.pl..\n";
    Output:
    # adult.pl:20: [0 .. 10, 16] # child.pl:16: [0 .. 10, 16, 72] # adult.pl:20: [0 .. 10, 16, 72, 52] # child.pl:16: [0 .. 10, 16, 72, 52, 17] # adult.pl:20: [0 .. 10, 16, 72, 52, 17, 66] # child.pl:16: [0 .. 10, 16, 72, 52, 17, 66, 96] # adult.pl:20: [0 .. 10, 16, 72, 52, 17, 66, 96, 92] # child.pl:16: [0 .. 10, 16, 72, 52, 17, 66, 96, 92, 88] # adult.pl:20: [0 .. 10, 16, 72, 52, 17, 66, 96, 92, 88, 56] Leaving child.pl.. Leaving adult.pl..

    * Note that they share data based on a named id, which means their connection can be established without the child script being started by the adult.