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
。这样更容易也更安全。
- 将
key = value
行拆分为键和值。
- 检查 "key" 是否为 "allowed_keys"。
- 如果是这样,将值拆分为 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');
我尝试提取一组值,在这种情况下,所有属于 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
。这样更容易也更安全。
- 将
key = value
行拆分为键和值。 - 检查 "key" 是否为 "allowed_keys"。
- 如果是这样,将值拆分为 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 fromsplit
直接进入循环外声明的@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');