绑定读取和写入Perl配置文件

绑定读取和写入Perl配置文件,perl,file,configuration,tie,Perl,File,Configuration,Tie,我正在使用我在上找到的PerlMonk示例: Configuration.pl: %CFG = ( 'servers' => { 'SRV1' => { 'IP' => 99.32.4.0, 'user' => 'aname', 'pswd' => 'p4ssw0rd', 'status' => 'unavailable'

我正在使用我在上找到的PerlMonk示例:

Configuration.pl:

%CFG = (
    'servers' => {
        'SRV1' => {
            'IP'     => 99.32.4.0,
            'user'   => 'aname',
            'pswd'   => 'p4ssw0rd',
            'status' => 'unavailable'
        },
        'SRV2' => {
            'IP'     => 129.99.10.5
            'user'   => 'guest',
            'pswd'   => 'guest'
            'status' => 'unavailable'
        }
    },
    'timeout' => 60,
    'log' => {
        'file'  => '/var/log/my_log.log',
        'level' => 'warn',
    },
    'temp' => 'remove me'
);
它工作得很好,但唯一的问题是读写类似散列的配置时“无序”。 有没有办法把它绑起来


这一点很重要,因为配置文件也将手动编辑,所以我希望键和值的顺序相同。

您可以在使用前将配置变量绑定到一起,这样以后的散列键将保持与以前相同的顺序

use strict;
use warnings;

use Tie::IxHash;
tie my %CFG, 'Tie::IxHash';

%CFG = (
    'servers' => {
        'SRV1' => {
            'IP'     => '99.32.4.0',
            'user'   => 'aname',
            'pswd'   => 'p4ssw0rd',
            'status' => 'unavailable'
        },
        'SRV2' => {
            'IP'     => '129.99.10.5',
            'user'   => 'guest',
            'pswd'   => 'guest',
            'status' => 'unavailable'
        }
    },
    'timeout' => 60,
    'log' => {
        'file'  => '/var/log/my_log.log',
        'level' => 'warn',
    },
    'temp' => 'remove me'
);

use Data::Dumper;
print Dumper \%CFG;
如果您使用,那么您的软件将不会受到恶意攻击(或者可能是意外损坏)。JSON的语法也比Perl数据结构简单,而且更容易从语法错误中恢复

设置
canonical
选项将创建具有排序顺序的键的数据,因此每次为相同的Perl数据生成相同的输出。如果您需要数据的特定顺序,而不是字母顺序,那么您可以使用@mpapec在其答案中描述的模块

或者,您可以使用纯Perl版本的模块中的
sort\u by
方法,该模块允许您传递排序规则子例程。这将允许您指定键的顺序,并且可以像使用哈希一样简单,该哈希将所有可能的键值与数字排序顺序关联起来

该程序使用
sort_by
方法按照与原始散列中出现的键相同的顺序重建JSON。这不太可能是你想要的顺序,但机制是存在的。它通过查找哈希表中的每个键来确定它们应该如何排序。默认情况下,哈希中未出现的任何键(如
SVR1
SVR2
)都按字母顺序排序

use strict;
use warnings;

use JSON::PP ();

my %CFG = (
  'servers' => {
    'SRV1' => {
      'IP'     => '99.32.4.0',
      'user'   => 'aname',
      'pswd'   => 'p4ssw0rd',
      'status' => 'unavailable'
    },
    'SRV2' => {
      'IP'     => '129.99.10.5',
      'user'   => 'guest',
      'pswd'   => 'guest',
      'status' => 'unavailable'
    }
  },
  'timeout' => 60,
  'log'     => {
    'file'  => '/var/log/my_log.log',
    'level' => 'warn',
  },
  'temp' => 'remove me'
);

my %sort_order;
my $n = 0;
$sort_order{$_} = ++$n for qw/ servers timeout log temp /;
$sort_order{$_} = ++$n for qw/ IP user pswd status /;
$sort_order{$_} = ++$n for qw/ file level /;

my $json = JSON::PP->new->pretty->sort_by(\&json_sort);
print $json->encode(\%CFG);

sub json_sort {
  my ($aa, $bb) = map $sort_order{$_}, $JSON::PP::a, $JSON::PP::b;
  $aa and $bb and $aa <=> $bb or $JSON::PP::a cmp $JSON::PP::b;
}

它可以简单地保存到文件中,并以类似的方式还原。

将数据存储为Perl代码是个坏主意。这样做会更好,这也解决了保持数据有序的问题。您还必须绑定所有内部哈希。您也可以将
$Data::Dumper::Sortkeys
设置为真值或对排序子例程的引用。@mob似乎有
Tie::Autotie
,但哈希值应该一次填充一个键/值。mpapec&@mob,谢谢,我会尝试一下。。。即使是你,将每个内部散列绑定起来似乎也是一个杀手锏。我同意JSON可能更好,特别是因为我正在考虑将来将这个项目从Perl迁移到Python。关于IP地址的问题,我同意,我已经把它改成了字符串,我使用的例子来自原始的例子帖子。我已经测试了两个选项。。。我的配置文件有太多的内部散列,我懒得把它们都绑起来。因此,使用带有规范标记的JSON是合乎逻辑且经济高效的。谢谢。@tal.tzf:很高兴您找到了解决方案。@tal.tzf:JSON的纯Perl实现提供了一个
sort_by
方法,允许您传递排序子例程。这可以让您指定键的顺序,也可以像使用散列一样简单,将所有可能的键值与数字排序顺序关联起来。@tal.tzf:我修改了我的答案,以显示如何通过使用
sort\u by
方法传递自定义排序子例程来生成您喜欢的任何键顺序。
{
   "servers" : {
      "SRV1" : {
         "IP" : "99.32.4.0",
         "user" : "aname",
         "pswd" : "p4ssw0rd",
         "status" : "unavailable"
      },
      "SRV2" : {
         "IP" : "129.99.10.5",
         "user" : "guest",
         "pswd" : "guest",
         "status" : "unavailable"
      }
   },
   "timeout" : 60,
   "log" : {
      "file" : "/var/log/my_log.log",
      "level" : "warn"
   },
   "temp" : "remove me"
}