Json Perl变量在循环中变得未定义
编辑:修改代码和输出,使其更清晰 编辑2:添加用于复制的示例输入 我有一个JSON文件和一个CSV文件,我正在对这两个文件进行比较。问题是$asset_ip在外部foreach循环中定义正确,但在嵌套循环中$asset_ip变得未定义 为什么$asset_ip变得未定义Json Perl变量在循环中变得未定义,json,perl,csv,Json,Perl,Csv,编辑:修改代码和输出,使其更清晰 编辑2:添加用于复制的示例输入 我有一个JSON文件和一个CSV文件,我正在对这两个文件进行比较。问题是$asset_ip在外部foreach循环中定义正确,但在嵌套循环中$asset_ip变得未定义 为什么$asset_ip变得未定义 #!/usr/bin/perl # perl -e'use CPAN; install "Text::CSV"' use strict; use warnings; use JSON::XS; use File::Slurp;
#!/usr/bin/perl
# perl -e'use CPAN; install "Text::CSV"'
use strict;
use warnings;
use JSON::XS;
use File::Slurp;
use Text::CSV;
my $csv = Text::CSV->new( { sep_char => ',' } );
my $csv_source = "servers.csv";
my $json_source = "assets.json";
my $dest = "servers_for_upload.csv";
# defined these here as I need to use them in foreach loop and if statement:
my $csv_ip;
my @fields;
open( my $csv_fh, '<', $csv_source ) or die "$! error trying to read";
open( my $dest_fh, '>', $dest ) or die "$! error trying to read";
my $json = read_file($json_source);
my $json_array = decode_json $json;
foreach my $item (@$json_array) {
my $id = $item->{id};
my $asset_ip = $item->{interfaces}->[0]->{ip_addresses}->[0]->{value};
# test the data is there:
if ( defined $asset_ip ) {
print "id: " . $id . "\nip: " . $asset_ip . "\n";
}
while (my $line = <$csv_fh>) {
chomp $line;
if ( $csv->parse($line) ) {
@fields = $csv->fields();
$csv_ip = $fields[0];
}
else {
warn "Line could not be parsed: $line\n";
}
if ( $csv_ip eq $asset_ip ) {
# preppend id to csv array and write these lines to new file
unshift( @fields, $id );
print $dest_fh join( ", ", @fields );
}
}
}
close $csv_fh;
注意,对于第一次迭代,$asset_ip将是未定义的。因此,如果定义了$asset_ip,我将修改代码以仅运行eq比较。然而,对于这个例子,我没有做检查,因为所有的迭代都是未定义的
servers.csv:
192.168.0.3,Brian,Germany
192.168.0.4,Billy,UK
192.168.0.5,Ben,UK
我认为你的问题是:
foreach my $line (<$csv_fh>) {
具体来说:
[{"id":1001,"interfaces":[]}
该数组中的第一个元素没有定义$asset\u ip
这意味着在您第一次通过时,$asset_ip未定义并生成错误。由于您的if定义测试,因此未打印任何行
但随后-代码继续遍历$csv_fh-读取到文件末尾-查找匹配项并失败3次,生成3条错误消息
第二次迭代-对于id 1002-IP无论如何都不在文件中,但是$csv_fh已经被读取到文件EOF的末尾-因此foreach循环根本不执行
这可以通过以下方式实现:
下一步添加其他内容;之后,如果定义。
在while循环之后添加seek。
但实际上,重写是正确的,这样你就不会一遍又一遍地阅读文件了
非常粗略地说:
#!/usr/bin/perl
# perl -e'use CPAN; install "Text::CSV"'
use strict;
use warnings;
use JSON::XS;
use File::Slurp;
use Text::CSV;
my $csv = Text::CSV->new( { sep_char => ',' } );
my $csv_source = "servers.csv";
my $json_source = "assets.json";
my $dest = "servers_for_upload.csv";
# defined these here as I need to use them in foreach loop and if statement:
my $csv_ip;
my @fields;
open( my $csv_fh, '<', $csv_source ) or die "$! error trying to read";
open( my $dest_fh, '>', $dest ) or die "$! error trying to read";
my $json = read_file($json_source);
my $json_array = decode_json $json;
foreach my $item (@$json_array) {
my $id = $item->{id};
my $asset_ip = $item->{interfaces}->[0]->{ip_addresses}->[0]->{value};
# test the data is there:
if ( defined $asset_ip ) {
print "id: " . $id . "\nip: " . $asset_ip . "\n";
}
else {
print "asset_ip undefined for id $id\n";
next;
}
while ( my $line = <$csv_fh> ) {
chomp $line;
if ( $csv->parse($line) ) {
@fields = $csv->fields();
$csv_ip = $fields[0];
}
else {
warn "Line could not be parsed: $line\n";
}
if ( $csv_ip eq $asset_ip ) {
# preppend id to csv array and write these lines to new file
unshift( @fields, $id );
print {$dest_fh} join( ", ", @fields ),"\n";
}
}
seek( $csv_fh, 0, 0 );
}
close $csv_fh;
我认为这还需要:
更改while,这样您就不会每次都重新读取该文件
您正在使用Text::CSV,因此使用打印连接,。。。这似乎不是一个一致的选择。如果您的数据支持Text::CSV,那么也值得保留它以供输出。
与您的问题无关:应该在die'$中使用双引号,而不是单引号!尝试读取“”时出错。按原样,您将获得美元!如果发生这些错误,则替换为变量的值。抱歉-没有提及-我在运行脚本时遇到错误$asset_ip未定义。引用错误消息和行号有助于诊断。一些示例源数据也是如此。大概这就是您正在使用的JSON?你有一些CSV样本数据吗?我认为没有必要包含样本数据。简单地说,$asset_ip在外循环中定义为ip地址,但在内循环中则未定义。第二个循环对CSV文件中的行数进行正确的迭代次数。如果没有样本数据,我们无法重现问题,因此只能猜测是哪一行导致问题,以及如何导致问题。这就是为什么我们通常要求一个-没有明确的原因为什么它会变得未定义或在哪里它会变得未定义。但是在阅读/重读$csv_fh时有一个明显的逻辑错误。我只是在编辑摘要中写了一个诙谐的评论…:我会想象一些有趣而有见地的事情。一般来说,如果你不得不对一个文件的内容进行多次迭代,重新读取该文件可能不是一个好主意,因为操作系统无论如何都会缓存数据。当然,在这种情况下,存在更有效的单通道算法description@IlmariKaronen:操作系统可能会缓存内容,Perl自己的I/O层可能会进行一些缓冲,但如果文件中有足够的数据,您将看到重复的读取系统调用,从而导致不必要的内核上下文切换。。。抱歉吹毛求疵-
[{"id":1001,"interfaces":[]},{"id":1003,"interfaces":[{"ip_addresses":[{"value":"192.168.0.2"}]}]},{"id":1004,"interfaces":[{"ip_addresses":[{"value":"192.168.0.3"}]}]},{"id":1005,"interfaces":[{"ip_addresses":[{"value":"192.168.0.4"}]}]}]
[{"id":1001,"interfaces":[]}
#!/usr/bin/perl
# perl -e'use CPAN; install "Text::CSV"'
use strict;
use warnings;
use JSON::XS;
use File::Slurp;
use Text::CSV;
my $csv = Text::CSV->new( { sep_char => ',' } );
my $csv_source = "servers.csv";
my $json_source = "assets.json";
my $dest = "servers_for_upload.csv";
# defined these here as I need to use them in foreach loop and if statement:
my $csv_ip;
my @fields;
open( my $csv_fh, '<', $csv_source ) or die "$! error trying to read";
open( my $dest_fh, '>', $dest ) or die "$! error trying to read";
my $json = read_file($json_source);
my $json_array = decode_json $json;
foreach my $item (@$json_array) {
my $id = $item->{id};
my $asset_ip = $item->{interfaces}->[0]->{ip_addresses}->[0]->{value};
# test the data is there:
if ( defined $asset_ip ) {
print "id: " . $id . "\nip: " . $asset_ip . "\n";
}
else {
print "asset_ip undefined for id $id\n";
next;
}
while ( my $line = <$csv_fh> ) {
chomp $line;
if ( $csv->parse($line) ) {
@fields = $csv->fields();
$csv_ip = $fields[0];
}
else {
warn "Line could not be parsed: $line\n";
}
if ( $csv_ip eq $asset_ip ) {
# preppend id to csv array and write these lines to new file
unshift( @fields, $id );
print {$dest_fh} join( ", ", @fields ),"\n";
}
}
seek( $csv_fh, 0, 0 );
}
close $csv_fh;