How can I print a variable and its value with just core Perl on RedHat?
I'm trying to create what should be a simple little sub in Perl that preferably does not use any modules not found in the standard RedHat linux distribution. In other words the more portable the better because I cannot always control which system environment I'm working in. The obvious problem is passing the variables to the subroutine so that both the original variable name and the value can be used. I can get one or the other but can't figure out how to do both without a more complex input for the sub call as shown below. I could pass a string and a reference but that would be almost as messy as just printing it locally with a simple:
print "\$A = $A\n";
There are also potential scope issues but one step at a time. I'm now thinking maybe this isn't that simple.
(Yes this is absolutely lazy programmer code I'm looking for)
Example Pseudo Code:
my $A = 1;
my $secondVar = "something new";
my $XXX = 12345;
# Print a listing of the variables of interest in a nice easy to read listing
# with a minimum of typing.
printVars( $A, $secondVar, $XXX );
# Note I could settle for passing by reference \$A but no more complicated than this in
# the sub call. This is just a little utility sub to use to double check variables while
# coding something new.
Output:
$A = 1
$secondVar = something new
$XXX = 12345
A rough SUB:
sub printVars {
my @ListOfVars = @_;
my $i;
my ($theVarName, $theVarValue);
for( $i=0; $i<@ListOfVars; $i++) {
$theVarName = ??; # This is where things break down.
$theVarValue = $ListOfVars[$i];
print "$theVarName = $theVarValue\n";
}
}
Thanks for any 开发者_如何学JAVAhelp you can render..
Enjoy.. --Bryan
If the approach using variable names suggested by Paul Tomblin and john is acceptable, you may want to pull in the Data::Dumper
module in order to be able to print out data structures.
Data::Dumper
has been part of the standard Perl5 distribution for a long time (I just verified on CPAN that it has been in 5.6, 5.8, and 5.10). If your OS vendor hasn't taken that apart in bizarre ways, there's no need to worry about Data::Dumper
not being there.
It really feels like you're trying to reinvent the wheel here, so I have to ask you for your motivations. There are plenty of existing mechanisms for helping you debug your code, including a built-in debugger (see perldoc perldebug and perldoc perldebugtut for the manual and tutorial), and a giant library of modules at CPAN. Anything you're thinking about building as a beginner has already been built, so unless you're doing this purely as a learning experience, you should use the tools that are already available to you.
Data::Dumper and Data::Dump are the usual ways of seeing the internals of a variable, not just simple strings as you are coding now but also deep and complicated data structures. Data::Dumper is part of many standard Perl installations, but anything distributed on CPAN is safe to depend on as it is easily installable on any system you are likely to encounter.
I don't think this can be done for lexical variables without resorting to PadWalker, so you may need to install that. Assuming you can, here is a working solution that allows for minimal call site syntax.
use PadWalker qw/peek_my peek_our/;
use Data::Dumper;
$Data::Dumper::Indent = 0; # or however pretty you want
sub inspect {
my $my = peek_my 1;
my $our = peek_our 1;
for (split(/\s+/ => "@_")) {
my $val = $$my{$_} || $$our{$_}
|| die "$_ not found";
print Data::Dumper->Dump(
/^\$/ ? ([$$val], [$_])
: ([ $val], ['*' . substr $_, 1])
) . "\n";
}
}
sub foo {
my $bar = shift;
inspect '$bar';
}
{ # closed scope
my $x = 'hello, world!';
my $y;
my @z = 1 .. 10;
our %global = (a => 1, b => [1 .. 3]);
my $ref = \%global;
inspect '$x $y @z %global $ref'; # qw/.../ can be used also
foo;
foo $x;
}
this prints out
$x = 'hello, world!';
$y = undef;
@z = (1,2,3,4,5,6,7,8,9,10);
%global = ('a' => 1,'b' => [1,2,3]);
$ref = {'a' => 1,'b' => [1,2,3]};
$bar = undef;
$bar = 'hello, world!';
you can pass the variable name as a scalar and then use referencing to print out the value. From perlref:
1. $name = "foo";
2. $$name = 1; # Sets $foo
3. ${$name} = 2; # Sets $foo
4. ${$name x 2} = 3; # Sets $foofoo
5. $name->[0] = 4; # Sets $foo[0]
6. @$name = (); # Clears @foo
7. &$name(); # Calls &foo() (as in Perl 4)
8. $pack = "THAT";
9. ${"${pack}::$name"} = 5; # Sets $THAT::foo without eval
See How can I use a variable as a variable name? for a viewpoint on using variables as variable names. Otherwise you have to use references as suggested by john and Paul Tomblin.
Pass in a list of variable names, and then print them out with
foreach $varname (@list)
{
print "$varname = $$varname\';
}
Actually, come to think of it, that won't work either, because $$ won't work because the variable won't be known to the sub. I don't think you'll be able to do what you want, short of putting all the variable names and values into a hash and dumping them with Data::Dumper. Normally at this point I'd delete this answer, but several other people have referenced it, so I won't.
use Data::Dumper;
print Dumper({"a" => $a, "cVar" => $cVar});
will produce something like:
$VAR1 = {
'a' => 'foo',
'cVar' => 'this is cVar'
};
No sub, but I recommend Smart::Comments
. It's as simple as this:
use Smart::Comments;
### $A
$A
will be shown in all it's glory, if 1) it does not have a dynamic cycle (as some Win32::OLE objects do), or if 2) it's not an "inside-out object", which is a pointer to a key to the data and not the data itself. The output is even more readable than Data::Dumper
(it uses Data::Dumper
behind the scenes, and so DD globals are usable, like $Data::Dumper::Deparse
(at the bottom of the linked list), for printing out subs.
And when you don't want to print out stuff, just comment out the use
statement. Then, they are just comments.
It's quite portable, as well. I simply transplanted Text::Balanced and Smart::Comments from my PC to an AIX box and voila. Done.
# A sub to print the value of any variable, scalar, array, or hash
sub strv
{ # edit structured things as a string for debugging
my ($v,$d) = @_;
my $s = '';
$d = 0 if not defined $d;
if (not defined $v)
{
$s.= (' 'x$d)."N";
}
elsif (ref($v) eq 'SCALAR')
{
if (! defined $$v)
{
my $null = 'NULL';
$v = \$null;
}
$s.= (' 'x$d)."S:$$v";
}
elsif (ref($v) eq 'ARRAY')
{
$s.= (' 'x$d)."A:(";
my $c = '';
my $x = 0;
foreach my $a (map(strv($_,0),@{$v}))
{
$s.= "$c$x:$a";
$c = ',';
$x++;
}
$s.= ")";
}
elsif (ref($v) eq 'HASH')
{
$d++;
$s.= "\n" if $s ne '';
while( my ($k, $x) = each %{$v} ) {
$s.= (' 'x$d)."H:".strv($k,$d+1).": ".strv($x,$d+1)."\n";
}
$s = substr($s, 0, -1);
}
elsif (ref($v))
{
$s.= ref($v);
}
$s.= (' 'x$d).'"'.$v.'"' if ref($v) eq '';
return $s;
} # sub strv
For the record here is an example of an actual solution as suggested by several of you using Data::Dumper. Hope it helps anyone looking for a simple sub to pretty print variables with very little effort. Thank you all!!
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
my @myArray = qw ( a b c d e f g h i j k );
# Showing Difference between shift and pop and what happens to @myArray
my ($A, $B, $C, $D,);
$A = shift @myArray;
$B = pop @myArray;
$C = shift @myArray;
$D = pop @myArray;
# prtVar() usage is close to original desired simplicity
# only needed to add the qw()
prtVar(qw ($A $B $C $D));
sub prtVar
{
my (@vars) = @_;
my $vname;
foreach $vname (@vars)
{
print Data::Dumper->Dump([eval($vname)], [$vname]);
}
}
Output:
$A = 'a';
$B = 'k';
$C = 'b';
$D = 'j';
精彩评论