PERL 从配置文件中提取值

PERL extract a values from a config file

我尝试提取一组值,在这种情况下,所有属于 allowed_hosts 的 ips 在我的 linux 系统的配置文件中。 所以我有这个:

configApp.cfg
bla bla bla
    ... 
allowed_hosts = 10.121.120.163,10.121.120.164, ips, ips, more ips ...
    ...
 something .

我已经阅读了网页http://perlmaven.com/how-to-extract-strings-from-a-file

但是我的凭证有一些问题。

open(my $file, '<:encoding(UTF-8)', $config_file)
  or die "Could not open file '$config_file' $!";
while (my $row = <$file>) {
 chomp $row;
 my @strings = $row =~ /[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/g;
 foreach my $s (@strings){
   print "'$s'";
 }
}

我希望能帮助我处理正则表达式。谢谢

分段处理解析问题通常更容易。查找 IP 地址是一个难题(只需等到有人将 IPv6 地址放在那里),并且该文件可能包含其他主机不允许的 IP 地址。如果你拿起 abnormal_hosts = 123.234.56.78 怎么办?

而是寻找 allowed_hosts = something。这样更容易也更安全。

  1. key = value 行拆分为键和值。
  2. 检查 "key" 是否为 "allowed_keys"。
  3. 如果是这样,将值拆分为 IP。

use strict;
use warnings;
use v5.10;

# Simulate the contents of a file.
my @Lines = (
"configApp.cfg\n",
"bla bla bla\n",
"\n",
"dangerous_hosts = 24.45.62.1\n",
"allowed_hosts = 10.121.120.163, 10.121.120.164 ,127.0.0.1,8.8.8.8\n",
" something .\n"
);

# Don't use a foreach loop to read a file, it wastes memory.
# This is for testing only.
for my $line (@Lines) {
    chomp $line;

    # Split the line into the key and value.
    # If it isn't a key = val line there will be no key.
    my($key, $val) = split /\s*=\s*/, $line;

    # If the key isn't there, or if it isn't "allowed_hosts", skip this line.
    next if !defined $key or $key ne 'allowed_hosts';

    # Now split the IP list. Be sure to account for whitespace.
    my @ips = split /\s*,\s*/, $val;

    say "Allowed Hosts: @ips";

    # We found the line, no need to read the rest of the file.
    last;
}

请注意,无需解析 IP 地址。所有程序关心的是它是一个逗号分隔的列表。如果你愿意,你可以验证 @ips 的内容,但现在你可以一次做一个,而不必解析行上的所有其他内容。

另请注意,我始终确保考虑 =, 等内容周围可能出现的空格。人们对放置空格的位置非常不一致。

分两步完成。首先提取 ip address/host 名称列表,然后使用 split 获取各个条目

if( $row =~ /^\s*allowed_hosts\s*=\s*(.*)/ ) {
  foreach my $s (split(/\s*,\s*/,)) {
    print("allowed: $s\n");
  }
}

如果你不想这样做,你可以试试这个:

while(my $row = <$file>) {
  chomp;
  print("'$_'\n") foreach (split(/\s*,\s*/,($row =~ /^\s*allowed_hosts\s*=\s*(.*)/i)[0]));
}

你可以这样做:

open(my $fh, '<', $config_file)
    or die "Could not open file '$config_file': $!";

while(<$fh>) {
    next until /^allowed_hosts = /;
    my @ips = /\d+[^\s,]+/g;
    print join "\n", @ips;
    last;
}

next until 会快速丢弃所有行,直到找到合适的行。
所有的匹配都存储在@ips变量中。
注意,因为你已经知道这一行包含ips,所以你不需要构建一个明确的模式来描述一个ip,你只需要避免空格和逗号。
last 停止循环。
很多情况下你不需要添加编码信息来打开你的文件,因为它可能完全是用 ASCII 字符编写的,就像许多配置文件一样,但我可能是错的。

注意,如果要使结果在循环外可用,则必须在循环外(循环之前)声明 @ips 变量。

考虑到您的具体问题,这是另一种方法

use warnings 'all';
use strict;
use feature 'say';

my $file = 'configApp.cfg';

open my $fh, '<', $file or die "Can't open $file: $!";

my @allowed_hosts;

while (<$fh>) 
{
    if (/^allowed_hosts\s*=\s*(.*)/) 
    { 
        my @hosts = split /\s*,\s*/, ; 
        push @allowed_hosts, \@hosts;
    }   
}

# Process hosts as needed
say "@$_" for @allowed_hosts;

评论

  • 仅处理具有所需 /^allowed_hosts/

  • 的行
  • 使用捕获的模式,在</code></p></li>中可用 <li><p>将包含一行结果的数组作为 <em>参考</em> 存储在包含所有结果的数组中</p></li> <li><p>如果<em>肯定</em>只有一个<code>/^allowed_hosts/行,那么就不需要另一个数组——store return from split 直接进入循环外声明的 @allowed_hosts 。然后你也可以在解析完这一行后退出循环。

对于多行(或文件),我们也可以使用匿名数组

if (/^allowed_hosts\s*=\s*(.*)/) 
{ 
    push @allowed_hosts, [ split /\s*,\s*/,  ];
}

但是,我们无法在将结果存储起来之前对其进行检查,而通过中介 @hosts 您可以根据需要添加检查或进一步验证、选择或处理。

与您张贴的文字完全一致

10.121.120.163 10.121.120.164 ips ips more ips ...
use strict;
use warnings;

use Config::Simple; # you may have to install this one

my $cfg = Config::Simple->new(configApp.cfg);

my @hosts = split " ", $cfg->param('allowed_hosts');

如果列表用位逗号而不是空格分隔,最后一行甚至会更具可读性,例如:

my @hosts = $cfg->param('allowed_hosts');