我尝试在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'";
}
}
我希望可以帮助我使用正则表达式。感谢
答案 0 :(得分:2)
通常更容易处理碎片中的解析问题。寻找IP地址是一个难题(只要等到某人将IPv6地址放入其中),该文件可能包含其他不允许主机的IP地址。如果你选择abnormal_hosts = 123.234.56.78
怎么办?
而是寻找allowed_hosts = something
。这更容易,更安全。
key = value
行拆分为键和值。
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]));
}