34

I know I can list all of the package and lexcial variables in a given scope using Padwalker's peek_our and peek_my, but how can I get the names and values of all of the global variables like $" and $/?

#!/usr/bin/perl

use strict;
use warnings;

use PadWalker qw/peek_our peek_my/;
use Data::Dumper;

our $foo = 1;
our $bar = 2;

{
    my $foo = 3;
    print Dumper in_scope_variables();
}

print Dumper in_scope_variables();

sub in_scope_variables {
    my %in_scope = %{peek_our(1)};
    my $lexical  = peek_my(1);
    #lexicals hide package variables
    while (my ($var, $ref) = each %$lexical) {
        $in_scope{$var} = $ref;
    }
    ##############################################
    #FIXME: need to add globals to %in_scope here#
    ##############################################
    return \%in_scope;
}
Chas. Owens
  • 64,182
  • 22
  • 135
  • 226

4 Answers4

33

You can access the symbol table, check out p. 293 of "Programming Perl" Also look at "Mastering Perl: http://www252.pair.com/comdog/mastering_perl/ Specifically: http://www252.pair.com/comdog/mastering_perl/Chapters/08.symbol_tables.html

Those variables you are looking for will be under the main namespace

A quick Google search gave me:

{
    no strict 'refs';

    foreach my $entry ( keys %main:: )
    {
        print "$entry\n";
    }
}

You can also do

*sym = $main::{"/"}

and likewise for other values

If you want to find the type of the symbol you can do (from mastering perl):

foreach my $entry ( keys %main:: )
{
    print "-" x 30, "Name: $entry\n";

    print "\tscalar is defined\n" if defined ${$entry};
    print "\tarray  is defined\n" if defined @{$entry};
    print "\thash   is defined\n" if defined %{$entry};
    print "\tsub    is defined\n" if defined &{$entry};
}
fido
  • 5,566
  • 5
  • 24
  • 20
8

And that does it. Thanks to MGoDave and kbosak for providing the answer in front of my face that I was too stupid to see (I looked in %main:: to start with, but missed that they didn't have their sigils). Here is the complete code:

#!/usr/bin/perl

use strict;
use warnings;

use PadWalker qw/peek_our peek_my/;
use Data::Dumper;

our $foo = 1;
our $bar = 2;

{
    my $foo = 3;
    print Dumper in_scope_variables();
}

print Dumper in_scope_variables();

sub in_scope_variables {
    my %in_scope = %{peek_our(1)};
    my $lexical  = peek_my(1);
    for my $name (keys %main::) {
        my $glob = $main::{$name};
        if (defined ${$glob}) {
            $in_scope{'$' . $name} = ${$glob};
        }

        if (defined @{$glob}) {
            $in_scope{'@' . $name} = [@{$glob}];
        }

        if (defined %{$glob}) {
            $in_scope{'%' . $name} = {%{$glob}};
        }
    }

    #lexicals hide package variables
    while (my ($var, $ref) = each %$lexical) {
        $in_scope{$var} = $ref;
    }
    return \%in_scope;
}
Chas. Owens
  • 64,182
  • 22
  • 135
  • 226
  • np, sometimes a push in the right direction is all that is needed. – fido Apr 14 '09 at 17:15
  • I got "Can't coerce GLOB to string in entersub"... which was cured by this suggestion: [https://apg.at.ufl.edu/wiki/Can't%20coerce%20GLOB%20to%20string%20in%20entersub]. – Marcus Apr 06 '12 at 21:58
5

You can do something like the following to check the symbol table of the main package:

{
    no strict 'refs';

    for my $var (keys %{'main::'}) {
        print "$var\n";
    }
}
Prashant Pokhriyal
  • 3,727
  • 4
  • 28
  • 40
kbosak
  • 2,132
  • 1
  • 13
  • 16
  • oops, took too long to post and MGoDave got in before me with the answer. But be sure to include no scrict 'refs' if you're using strict or you'll get an error. – kbosak Apr 14 '09 at 15:53
  • Actually, turns out it was just the way I coded mine.. you can do it with strict the way your code is (ie. keys %main:: without quotes) – kbosak Apr 14 '09 at 16:14
  • Did you actually try that? %main:: does not contain global variables, only package variables declared in the main package. I am looking for the global variables like $/. – Chas. Owens Apr 14 '09 at 16:32
  • I did try and it does in fact contain global variables – fido Apr 14 '09 at 16:35
  • I take it back, I just didn't recognize them because the are missing their sigils. Hmm, how to figure out if they are arrays, hashes, or scalars. – Chas. Owens Apr 14 '09 at 16:37
  • look at my answer, in the comments :) – fido Apr 14 '09 at 16:39
1

Thanks, Chas, very useful code. As a note for future users of your code with perl > 5.12:

I was using it in in my pdl2 .perldlrc to find out lexical variables (like the 'y' command in the debugger) and I had this warning:

load_rcfile: loading

/homes/pmg/.perldlrc defined(%hash) is deprecated at (eval 254) line 36.

    (Maybe you should just omit the defined()?)

From perldoc -f defined

Use of defined on aggregates (hashes and arrays) is deprecated. It used to report whether memory for that aggregate had ever been allocated. This behavior may disappear in future versions of Perl. You should instead use a simple test for size:

>     if (@an_array) { print "has array elements\n" }
>     if (%a_hash) { print "has hash members\n" }

What I don't understand is why it only complained with the defined hash and not also with the array?

Pablo Marin-Garcia
  • 4,151
  • 2
  • 32
  • 50
  • 2
    There is definitely code to print a similar warning for arrays (see around line 7813 of op.c), but `perl -we '@a = defined @a'` doesn't seem to trigger it, but `perl -we '%h = (1,defined %h)'` definitely does trigger a warning. This smells like a bug of some form. – Chas. Owens Jul 09 '11 at 00:29
  • 2
    Interesting, you can trigger the warning with this `perl -wE 'my @a;say defined @a ? @a : "f"'`, but not this `perl -wE 'our @a;say defined @a ? @a : "f"'`. This seems to say that only actual lexical variables will throw the warning. – Chas. Owens Jul 09 '11 at 10:27