我正在阅读一个文件standard.p.config
,其行有缩进。
该文件包含必须从服务器填写的字段。
检索值后,程序会创建一个输出文件,并为字段填充字段值。
但是当标准文件有缩进时,输出文件不会填充正确的值。
我在输出文件中需要这些缩进以供进一步处理。
standard.p.config
文件
DESCRIPTION: Config for lddfvt testcases
AUTO_PROVISIONED:
HMC_HMC1_NAME:
HMC_HMC1_PASS:abc123
MANAGEDMC_MANAGEDMC_NAME:p9zzd-fsp
LPAR_LPAR1_NAME:
LPAR_LPAR1_PASSWD:passw0rd
LPAR_LPAR2_NAME:
LPAR_LPAR2_PASSWD:passw0rd
os_env:AIX
nodecount:2
default_host:host1
default_con_mode:telnet
host1:$LPAR_LPAR1_NAME
host1_login:root
host1_password:$LPAR_LPAR1_PASSWD
host1_test_slot:
host1_test_slot1:
host1_test_slot2:
exact_match_mcast_counter:32
host2:$LPAR_LPAR2_NAME
host2_login:root
host2_password:$LPAR_LPAR2_PASSWD
host2_pp_slot:
host2_pp_slot1:
back_to_back_setup:
switch1:
switch1_vendor:BNT
switch1_login:admin
switch1_password:admin
host1_switch1_port1:
host1_switch1_port2:
host2_switch1_port1:
host1_test_ip1:
host2_test_ip1:
host1_test_ip2:
host2_test_ip2:
ip_netmask:255.255.255.0
mcast_ip1:225.1.2.6
mcast_ip2:225.1.2.7
unicast_test_mac:0x00:11:22:22:33:33
vlan_tag_id:
vlan_tag_id2:
long_run_duration:1
eid_run_duration:1
FIRING_NODE:$LPAR_LPAR3_NAME
SCRIPTS: ~
直到LPAR_LPAR2_PASSWD
它有两个缩进,然后每行一个缩进。
这个代码
open FILE1, "/home/jenkins/config/standard.p.config" or die;
my %hash;
while ( my $line = <FILE1> ) {
chomp( $line );
( my $word1, my $word2 ) = split /:/, $line; #/
my $config_filename = "/home/jenkins/config/$filename";
# write a switch to match your variable and fill in place of word2;
# if paattn matches then $word2=$var;
# $hash{$word1} = $word2;
switch ( $word1 ) {
case "LPAR_LPAR1_NAME" { $word2 = "$host1" }
case "LPAR_LPAR2_NAME" { $word2 = "$host2" }
case "host1_test_slot" { $word2 = "$host1_test_slot" }
case "host1_test_slot1" { $word2 = "$host1_test_slot1" }
case "host1_test_slot2" { $word2 = "$host1_test_slot2" }
case "host2_pp_slot" { $word2 = "$host2_pp_slot" }
case "host2_pp_slot1" { $word2 = "$host2_pp_slot1" }
case "switch1" { $word2 = "$Switch_IP" }
case "host1_switch1_port1" { $word2 = "$host1_switch1_port1" }
case "host1_switch1_port2" { $word2 = "$host1_switch1_port2" }
case "host2_switch1_port1" { $word2 = "$host2_switch1_port1" }
case "host1_test_ip1" { $word2 = "$host1_test_ip1" }
case "host1_test_ip2" { $word2 = "$host1_test_ip2" }
case "host2_test_ip1" { $word2 = "$host2_test_ip1" }
case "host2_test_ip2" { $word2 = "$host2_test_ip2" }
case "vlan_tag_id" { $word2 = "$vlan_tag_id" }
case "vlan_tag_id2" { $word2 = "$vlan_tag_id2" }
case "back_to_back_setup" { $word2 = "$back_to_back_setup" }
case "vlan_tag_id2" { $word2 = "$vlan_tag_id2" }
case "back_to_back_setup" { $word2 = "$back_to_back_setup" }
case "HMC_HMC1_NAME" { $word2 = "$HMC_HMC1_NAME" }
case "unicast_test_mac" { $word2 = "0x00:11:22:22:33:33" }
}
$hash{$word1} = $word2;
open( my $fh, '>', $config_filename ) or die "Could not open file '$config_filename' $!";
print $fh Dump \%hash;
close $fh;
}
答案 0 :(得分:1)
有一些直接错误,首先要解决它们。最后会有一些评论。
case
声明
当您在引号(case
)下使用"..."
值时,会测试它与switch
值的相等性,在这种情况下,它会使用{{1}测试字符串相等性}。
但是eq
所有$word1
都有前导空格,由split /:/
保留。这满足了保留它们的要求,但case
值中没有一个具有前导空间,因此测试失败。
您想要使用正则表达式匹配
switch ($word1) {
case /\bLPAR_LPAR1_NAME\b/ { $word2 = $host1 }
...
}
表示$word1 =~ m/\bLPAR_LPAR1_NAME\b/
,并根据您的文件匹配。
需要字边界锚点\b
来区分彼此包含的字符串,例如host
和host1
以及host1_test_slot
。感谢Borodin发表评论。有关初学者的信息,请参阅perlretut。
您似乎正在使用Switch模块。请注意,它是一个具有非常复杂行为的源过滤器。我建议选择其他结构。下面我使用简单的级联if-elsif
作为switch
功能的最直接匹配。
输出文件
每次循环都会打开和写入,每次都会覆盖上一次迭代中写入的那个。循环完成后写输出文件。感谢thanos发表评论。
选择用于汇总结果的数据结构
配置文件显然依赖于行的顺序。在输出中,行AUTO_PROVISIONED:
必须跟在输入后面跟随它的相同行。但是,使用散列来组装标记值对会拒绝这一点,因为Perl中的散列本质上是无序的。您可以使用模块保持散列的顺序,但使用数组来收集输出行要简单得多。
这方面的另一个问题是你究竟需要做什么。仅提供缺失值?还有其他方法可以进行处理,但由于问题中没有说明目标,我只能提出这一点。我只是用最直接的替代方案替换switch
。
您将诊断输出“转储”到磁盘而不说明使用了哪个模块,我宁愿不猜测提供Dump
功能的是什么(它不是Data::Dumper)。相反,为什么不写一个配置文件?
提供值的变量是未定义的,因此我只使用字符串文字包含少数几种情况。
use warnings;
use strict;
use feature 'say';
my $file = 'standard.p.config';
open my $fh, '<', $file or die "Can't open $file: $!";
my $outfile = $file . '.new';
my @out_lines;
while (my $line = <$fh>) {
chomp($line);
(my $word1, my $word2) = split /:/, $line; #/ preserves indentation
$_ = $word1; # for cleaner regex below
if (/\bLPAR_LPAR1_NAME\b/) { $word2 = 'host1' } # $host1 not given..
elsif (/\bLPAR_LPAR2_NAME\b/) { $word2 = 'host' }
elsif (/\bhost1_test_slot\b/) { $word2 = 'host1_test_slot' }
...
elsif (/\bunicast_test_mac\b/) { $word2 = '0x00:11:22:22:33:33' }
push @out_lines, "$word1: $word2";
}
close $fh;
open my $fh_out, '>', $outfile or die "Can't open $outfile: $!";
say $fh_out $_ for @out_lines;
close $fh_out;
考虑更多描述性变量名称而不是$wordN
(例如,tag
和value
)。在定义字符串后,请将字符串('host'
)替换为变量($host
)。
评论
始终在程序顶部use warnings;
和use strict;
没有理由对变量($word2 = "$host1"
)进行双引号;无论如何,它都会被评估。它只会产生误导,甚至会导致细微的问题
open中的词法文件句柄(my $fh
)明显优于globs(FILE1
)
使用die
打印实际错误时,至少为die $!
。
请参阅Error variables in perlvar
感谢Borodin发表评论。