【问题标题】:How can I print a variable and its value with just core Perl on RedHat?如何在 RedHat 上仅使用核心 Perl 打印变量及其值?
【发布时间】:2010-01-23 18:42:18
【问题描述】:

我正在尝试在 Perl 中创建一个简单的小子,最好不要使用标准 RedHat linux 发行版中没有的任何模块。换句话说,越便携越好,因为我不能总是控制我在哪个系统环境中工作。明显的问题是将变量传递给子例程,以便可以使用原始变量名称和值。我可以得到一个或另一个,但如果没有更复杂的 sub 调用输入,我无法弄清楚如何做到这两个,如下所示。我可以传递一个字符串和一个引用,但这几乎就像用一个简单的本地打印它一样混乱:

print "\$A = $A\n"; 

也存在潜在的范围问题,但一步一步来。我现在在想,也许这不是那么简单。

(是的,这是我正在寻找的绝对懒惰的程序员代码)

示例伪代码:

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.

输出:

$A = 1
$secondVar = something new
$XXX = 12345

一个粗略的 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";
    }
}

感谢您提供的任何帮助..

享受.. --布莱恩

【问题讨论】:

  • 您正在寻找一种用于转储变量的便携式解决方案:使用 Data::Dumper。我不明白你的论点,你想让我们提供一个纯粹的 perl 转储变量的方法吗? Data::Dumper 自 5.005 以来一直在 CORE 中。假设它不存在,只需安装它,如果您想要它的源代码,而不是要求人们重建它,只需转到 cpansearch.perl.org/src/SMUELLER/Data-Dumper-2.125/Dumper.pm 并获取纯 perl 源代码。此外,DD 也有一个 XS 变体,如果可用,它将使用它。
  • 只想对大家说声谢谢。显然 Data::Dumper 是一个合理且受核心支持的解决方案。我想我们已经讨论了这个话题。

标签: perl


【解决方案1】:

如果 Paul Tomblin 和 john 建议的使用变量名的方法是可以接受的,您可能需要引入 Data::Dumper 模块以便能够打印出数据结构。

Data::Dumper 长期以来一直是标准 Perl5 发行版的一部分(我刚刚在 CPAN 上验证它已经在 5.6、5.8 和 5.10 中)。如果您的操作系统供应商没有以奇怪的方式将其分解,则无需担心Data::Dumper 不存在。

【讨论】:

  • 代码需要可移植。我并不总是能够控制我正在运行的 perl 构建。谢谢..--布莱恩
  • 您应该始终拥有 Data::Dumper。
  • Data::Dumper 是核心 Perl 发行版的一部分,应该可以在任何 Perl 安装中使用。
  • 最棒的!!我刚刚检查了一下,我的服务器场上使用的 OSX 10.6.2 Perl 5.10.1、RedHat Enterprise 4 Perl 5.8.5 和 RedHat Enterprise 5 Perl 5.8.8 似乎都在使用 Data::Dumper 所以也许我的状态更好比我想象的要好。猜猜我做这件事太久了,错过了所有这些很酷的新(好吧我猜不是那么新)添加......谢谢你的提示! (当然还有建议 Data:Dumper 的每个人)看起来我可以转储我的变量...(双关语)感谢所有帮助。
【解决方案2】:

感觉就像你在这里重新发明轮子一样,所以我不得不问你的动机。有很多现有的机制可以帮助您调试代码,包括内置调试器(参见 perldoc perldebugperldoc perldebugtut 以获取手册和教程),以及位于 CPAN 的巨大模块库。作为初学者,您正在考虑构建的任何东西都已经构建,因此除非您只是将其作为一种学习体验,否则您应该使用您已经可用的工具。

Data::DumperData::Dump 是查看变量内部的常用方法,不仅是您现在编码的简单字符串,还包括深度和复杂的数据结构。 Data::Dumper 是许多标准 Perl 安装的一部分,但 CPAN 上分发的任何内容都可以安全地依赖,因为它可以轻松安装在您可能遇到的任何系统上。

【讨论】:

  • 这与模块不存在并且我无法安装它们的情况有关。换句话说,环境超出了我的控制,或者我的客户不愿意添加模块。同样在其他环境(Linux、OSX、Windows)中工作,每个 perl 环境都有点不同,你不能总是依赖那里的调试器和模块。综上所述,我开始这个练习是因为我认为这是一个容易编写的子,然后碰到了这堵墙。这应该很容易,但似乎并不容易。
  • @Bryan:您的情况是一个非常常见的问题(例如,请参阅stackoverflow.com/search?q=[perl]+install+external+modules 了解有关安装模块的各种方案的许多讨论),但您始终可以简单地复制数据源::如果您不能要求客户安装模块,请使用自卸车。但是调试器是本地 Perl 的一部分,所以它总是可用。 (不,转储变量的内容并不容易,正如您通过检查 Data::Dumper 的来源所看到的那样 - 有很多边缘情况需要考虑。)您正在尝试在这里重新发明轮子。
  • 是的,不属于标准发行版的模块的危险部分是,如果您开始使用它们并分支到您的代码开始依赖它们的地方,它会使代码在关于从一种环境到另一种环境的运输。然后你进入 require 和模块检查,这一切都变得疯狂,当你的客户尝试在其他地方使用代码时会感到不安。当商业 EDA 工具的需求不属于我们的环境时,我会经常处理它。让你发疯,但这是一种生活!!谢谢!!
  • 好吧,我承认 DataDumper 不属于我上面提到的那个“危险”类别。我只是忘记了过去几年中添加到核心构建中的所有模块。
  • @Bryan:你可能对stackoverflow.com/questions/2049735/…感兴趣
【解决方案3】:

我认为不借助 PadWalker 就无法对词法变量执行此操作,因此您可能需要安装它。假设您可以,这里有一个可行的解决方案,它允许使用最少的调用站点语法。

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;
}

打印出来

$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!';

【讨论】:

    【解决方案4】:

    您可以将变量名称作为标量传递,然后使用引用来打印出值。来自 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
    

    【讨论】:

      【解决方案5】:

      有关使用变量作为变量名的观点,请参阅How can I use a variable as a variable name?。否则,您必须按照 john 和 Paul Tomblin 的建议使用引用。

      【讨论】:

      • 是的,我读过并尊重意见,但在这种情况下,这是我正在尝试构建的实用程序。一般来说,我不会使用这样的变量名,但出于这个目的,为了使子调用尽可能简单,我认为这是一个要求。 --布莱恩
      【解决方案6】:

      传入一个变量名列表,然后用

      打印出来
      foreach $varname (@list)
      {
         print "$varname = $$varname\';
      }
      

      实际上,想想看,这也行不通,因为 $$ 行不通,因为 sub 不知道该变量。我不认为你能做你想做的事,除了将所有变量名和值放入一个散列并用 Data::Dumper 转储它们。通常此时我会删除这个答案,但其他几个人已经引用了它,所以我不会。

      use Data::Dumper;
      print Dumper({"a" => $a, "cVar" => $cVar});
      

      会产生类似的东西:

      $VAR1 = {
                'a' => 'foo',
                'cVar' => 'this is cVar'
              };
      

      【讨论】:

      • 嗯.. 这个 sub 的关键是它的语法非常简单。必须比简单的打印语句更简单。 prtVar( $var1, $var2 ) 所以如果我使用: prinVar( qw ($var1, $var2)) 这会很接近,但 sub 不能正确处理列表。必须考虑一下..--Bryan
      • 你所要求的,传入一个变量然后知道变量名是什么的能力,是不可能的。
      • OK Paul... 很公平,sub 将无法从值传递中重新构造原始变量名称。因此,传递变量名将是唯一的解决方案,但如果没有 CPAN 模块,它似乎会直接引用该变量名的值。好吧,我还没有完成所有其他上传的代码,看看它是否有效。感谢您的意见...
      • 使用 PadWalker 等模块并非不可能。但是,我不推荐所有可能的方法。 :)
      【解决方案7】:

      没有子,但我推荐Smart::Comments。就这么简单:

      use Smart::Comments;
      ### $A
      

      $A 将在其全部荣耀中显示,如果 1) 它没有动态循环(如某些 Win32::OLE 对象那样),或者如果 2) 它不是“由内而外的对象”,即是指向数据键的指针,而不是数据本身。输出比Data::Dumper 更具可读性(它在幕后使用Data::Dumper,因此可以使用DD 全局变量,例如$Data::Dumper::Deparse(位于链接列表的底部),用于打印出subs。

      当您不想打印内容时,只需将use 语句注释掉即可。那么,他们只是cmets。

      它也很便携。我只是将 Text::Balanced 和 Smart::Comments 从我的 PC 移植到 AIX 机器上,瞧。完成。

      【讨论】:

        【解决方案8】:
        # 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
        

        【讨论】:

        • Hey Don... 这看起来需要将变量名称/数据对传递给它。在使用 sub 时,从语法的角度来看,这并不比简单的 print 语句容易得多。谢谢..
        【解决方案9】:

        为了记录,这里是几个实际解决方案的示例 你们使用 Data::Dumper。希望它可以帮助任何寻找简单子的人 用很少的努力漂亮地打印变量。谢谢大家!!

        #!/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]);
                }
            }
        

        输出:

        $A = 'a';
        $B = 'k';
        $C = 'b';
        $D = 'j';
        

        【讨论】:

        • @Bryan => 这是因为 my 变量在定义 prtVar 时在范围内。如果您将sub 声明移到my 变量上方,它将不再起作用。请参阅我的答案,了解适用于封闭范围(块、子...)的解决方案
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-26
        • 1970-01-01
        • 2012-08-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多