PERL从配置文件中提取值

时间:2016-10-07 20:23:11

标签: regex linux perl config

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

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

我希望可以帮助我使用正则表达式。感谢

5 个答案:

答案 0 :(得分:2)

通常更容易处理碎片中的解析问题。寻找IP地址是一个难题(只要等到某人将IPv6地址放入其中),该文件可能包含其他不允许主机的IP地址。如果你选择abnormal_hosts = 123.234.56.78怎么办?

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

  1. key = value行拆分为键和值。
  2. 检查&#34;键&#34;是&#34; allowed_keys&#34;。
  3. 如果是,请将值拆分为IP。
  4. 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的内容,但现在您可以一次执行一项,而无需解析该行上的所有其他内容。

    另请注意,我始终确保考虑=,等可能的空格。人们对于他们放置空间的位置确实不一致。

答案 1 :(得分:2)

你可以这样做:

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变量。

答案 2 :(得分:0)

根据您的具体问题,这是另一种方法

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*/, $1; 
        push @allowed_hosts, \@hosts;
    }   
}

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

评论

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

  • 的行
  • 使用$1

  • 中提供的捕获模式
  • 将包含结果的数组存储为具有所有结果的数组引用

  • 如果肯定只有一条/^allowed_hosts/行,那么就不需要另一个数组 - 从split直接存储到@allowed_hosts在循环之外声明。然后,您可以在解析此行后退出循环。

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

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

然而,在我们将结果存在之前,我们无法检查结果,而使用中间@hosts,您可以添加检查或进一步验证或选择或处理(如果需要)。

使用您发布的确切文本打印

10.121.120.163 10.121.120.164 ips ips more ips ...

答案 3 :(得分:0)

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');

答案 4 :(得分:-1)

分两步完成。首先提取IP地址/主机名列表,然后使用拆分来获取各个条目

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

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

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