【问题标题】:Reading/dumping a perl hash from shell从 shell 读取/转储 perl 哈希
【发布时间】:2017-11-11 00:27:26
【问题描述】:

我有一个只读的 perl 文件,其中定义了一个巨大的哈希值。无论如何我可以阅读这个 perl 文件并转储散列内容吗?

这是文件中哈希的基本结构。

%hash_name = {
    -files => [
         '<some_path>',
    ],
    -dirs => [
         '<some_path>',
         '<some_path>',
         '<some_path>',
         '<some_path>',
         '<some_path>',
    ],
};

【问题讨论】:

  • 你能不能不 cat 文件并将其重定向到一个有写权限的文件? cat perl_file_name &gt; new_perl_file_name
  • 是的,我确实考虑过,但只有在没有其他方法可以在不创建新文件的情况下转储哈希时才会采用这种方法。
  • @newbie 谢谢,并重复这个问题:这个文件有其他 Perl 代码还是只有这个哈希?此外,哈希是未声明的(只是%hash_name),正如您所展示的那样,还是“词法”,所以my 例如:my %hash_name
  • @newbie 你显示的在 Perl 中是无效的:%hash_name 中的 % 表示变量是 hash,但 { .. } 形成 散列引用,它是一个标量变量(不是散列)。所以它应该是%hash_name = ( .. ) 或者它是$hashref_name = { .. }
  • 请注意,这是一种不安全的数据存储方式。数据文件必须作为 perl 代码进行评估。任何任意代码都可以在文件中。此外,数据文件只能由 Perl 程序读取。而是使用 JSON 或类似的数据格式。 JSON::MaybeXS 可以在 JSON 和 Perl 之间进行转换。

标签: perl data-dumper perl-hash


【解决方案1】:

理想情况下,您应该复制文件以便对其进行编辑,然后将其转换为 模块 以便很好地使用它。

但如果由于某种原因这不可行,这里是您的选择。

如果该哈希是文件中唯一的内容,则使用do“加载”它并分配给一个哈希

use warnings;
use strict;

my $file = './read_this.pl';  # the file has *only* that one hash

my %hash = do $file;

do 的这种形式执行文件(将其作为脚本运行),返回最后计算的表达式。只有文件中的哈希,最后一个表达式就是哈希定义,这正是您所需要的。

如果散列未声明,所以是一个全局变量(或用our 声明),然后在您的程序中声明为our 一个具有相同名称的散列并再次加载文件do

our %hash_name;  # same name as in the file
do $file;        # file has "%hash" or "our %hash" (not "my %hash")

在这里,我们“拾取”评估为 do 的哈希值通过 our 运行文件

如果散列是“词法”,声明为my %hash(应该如此!)......好吧,这很糟糕。然后你需要解析文件的文本以便提取带有哈希的行。这通常非常很难做到,因为它相当于解析 Perl。 (可以使用map 构建散列,从作为引用或平面列表的子返回...)一旦完成,您eval 将包含定义该散列的文本的变量。

但是,如果您知道哈希是如何构建的,正如您所暗示的那样,内部任何地方都没有 ()

use warnings; 
use strict;

my $file = './read_this.pl';

my $content = do {  # "slurp" the file -- read it into a variable
    local $/;
    open my $fh, '<', $file or die "Can't open $file: $!";
    <$fh>;
};

my ($hash_text) = $content =~ /\%hash_name\s*=\s*(\(.*?\)/s;
my %hash = eval $hash_text;

这个简单的镜头遗漏了很多,假设散列如图所示。另请注意,这种形式的eval 会带来真实而严重的安全风险。


文件也使用require 加载。除了它比do 做得更多之外,重要的是即使它运行多次require 仍然会加载该文件只加载一次。这首先对模块很重要,不应该多次加载,use 确实使用了require

另一方面,do 每次都会这样做,是什么使它适合加载用作数据的文件,大概应该每次都读取。这是推荐的方法。注意require 本身使用do 来实际加载文件。

感谢Schwern 的评论。

【讨论】:

  • do 将始终加载文件。 require 只会加载一次。由于要从文件中获取数据,建议使用do。否则第二次或第三次该过程中的任何内容都会加载文件,它们最终会得到1
  • @Schwern 对,谢谢你的评论。我想避免过多的解释,因此我只使用do。 (我仍然提到require,因为数据加载一次是可行的。)但是很高兴说明这一点,谢谢-我正在添加评论。
  • 使用require 是不好的做法,因为将来维护代码的人也可能在其他地方require 同一个文件(即使在同一个代码文件中,它是每个进程)并且没有意识到它有已经被要求了。我建议改为解释为什么 do 是正确的做法,而不是 require,这是必要的复杂性。
  • 我希望我可以给这两个赞,一个是给了很好的答案,另一个是在你的解决方案中包含use warnings; use strict;,因为这么多开始关注这个的程序员会看到它很重要为了始终保持这些状态,我看到很多初学者的 perl 程序员不把它们放在上面,然后提出一些问题,这些问题本来可以通过包含警告和严格来避免的。总的来说,这是一个非常好的和彻底的答案!
  • @DavyM 谢谢你的好话。你是对的,这样的问题太多了,以至于当人们刚开始时,它甚至看起来常见(比其他情况)。我们所能做的就是不断指出它,并始终以完整的代码示例编写它。
猜你喜欢
  • 2012-12-11
  • 1970-01-01
  • 2016-08-04
  • 2014-07-13
  • 1970-01-01
  • 2016-07-22
  • 2011-04-01
  • 1970-01-01
  • 2015-04-25
相关资源
最近更新 更多