getting new variables into a pre-existing variable perl - perl

I have a script that prints out a string of values which are pipe delimited.
waht i want to do is is if $f3 field equals something, like the letter C
I want it to print out the xout.
However if the $f3 is not populated with any value, I want N and G to be
printed out in the $f5 and F7 fileds respectively.
#!/usr/bin/perl
use strict;
use warnings;
my ( $system, $f2, $f3, $f4, $f5, $f6, $f7 ) = "";
#$f3="C";
my $xout = "$system|$f2|$f3|$f4|$f5|$f6|$f7|\n";
if ( defined $f3 && $f3 ne '' ) {
print $xout;
print "\$f3 is defined \n";
} else {
my $f5 = "N";
my $f7 = "G";
print $xout;
print "the 7th and 8th blocks should have values \n";
}
This is the output
Use of uninitialized value $f2 in concatenation (.) or string at ./test_worm_output line 6.
Use of uninitialized value $f3 in concatenation (.) or string at ./test_worm_output line 6.
Use of uninitialized value $f4 in concatenation (.) or string at ./test_worm_output line 6.
Use of uninitialized value $f5 in concatenation (.) or string at ./test_worm_output line 6.
Use of uninitialized value $f6 in concatenation (.) or string at ./test_worm_output line 6.
Use of uninitialized value $f7 in concatenation (.) or string at ./test_worm_output line 6.
|||||||
the 7th and 8th blocks should have values
If the f is uncommented I get :
(lots of uninitialized values lines)
||C|||||
$f3 is defined
what i want is if the f not defined, if is has no value I need it to print out
||||N||G|
ultimately the lines will look like this (the other fields will have values )
but if that third values is populated, I can't have the N or G and if $f3 is blank
I need the N and G.
host1||C|||||
host2||C|||||
host3||||N||G|
host4||C|||||
host5||||N||G|
thank you

In the line
my ($system ,$f2,$f3,$f4,$f5,$f6,$f7) = "" ;
you're only initializing the first variable in the list, $system. To initialize all of the variables in the list, you need an equal number of values on the RHS:
my ($system, $f2, $f3, $f4, $f5, $f6, $f7) = ("", "", "", "", "", "", "");
or
my ($system, $f2, $f3, $f4, $f5, $f6, $f7) = ("") x 7;
However, any time you find yourself creating numbered variables (e.g. f1, f2, f3) you should think "array" instead:
my #fields = ("") x 7;
if ($fields[2] eq "") {
#fields[4, 6] = ("N", "G");
}
print join("|", #fields), "\n";
Output:
||||N||G
(Of course, this code is rather pointless since we explicitly set $fields[2] to the empty string and then check if it's equal to...the empty string. I assume your actual code is more complex.)
In your case, it looks like the first field is distinct from the rest, so it would make more sense to store your data in a hash of arrays (assuming the hostnames are unique):
use strict;
use warnings;
# Populate the hash
my %data;
foreach my $host_num (1..5) {
my #fields = ("") x 6;
$fields[1] = "C" if $host_num == 1 or $host_num == 2 or $host_num == 4;
my $host_name = "host" . $host_num;
$data{$host_name} = [ #fields ];
}
# Print the contents
foreach my $host (sort keys %data) {
if ($data{$host}[1] eq "") {
#{ $data{$host} }[3, 5] = ("N", "G");
}
print join("|", $host, #{ $data{$host} }), "\n";
}
Output:
host1||C||||
host2||C||||
host3||||N||G
host4||C||||
host5||||N||G

Related

SOLVED: Hash content access is inconsistent with different perl version

I came across an interesting problem with following piece of code in perl 5.22.1 and perl 5.30.0
use strict;
use warnings;
use feature 'say';
#use Data::Dumper;
my %hash;
my %seen;
my #header = split ',', <DATA>;
chomp #header;
while(<DATA>) {
next if /^\s*$/;
chomp;
my %data;
#data{#header} = split ',';
push #{$hash{person}}, \%data;
push #{$hash{Position}{$data{Position}}}, "$data{First} $data{Last}";
if( ! $seen{$data{Position}} ) {
$seen{$data{Position}} = 1;
push #{$hash{Role}}, $data{Position};
}
}
#say Dumper($hash{Position});
my $count = 0;
for my $person ( #{$hash{person}} ) {
say "Person: $count";
say "Role: $person->{Position}";
}
say "---- Groups ----\n";
while( my($p,$m) = each %{$hash{Position}} ) {
say "-> $p";
my $members = join(',',#{$m});
say "-> Members: $members\n";
}
say "---- Roles ----";
say '-> ' . join(', ',#{$hash{Role}});
__DATA__
First,Last,Position
John,Doe,Developer
Mary,Fox,Manager
Anna,Gulaby,Developer
If the code run as it is -- everything works fine
Now it is sufficient to add $count++ increment as bellow and code produces errors
my $count = 0;
for my $person ( #{$hash{person}} ) {
$count++;
say "Person: $count";
say "Role: $person->{Position}";
}
Errors:
Error(s), warning(s):
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 24, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 3.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 3.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 4.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in join or string at source_file.pl line 48, <DATA> line 4.
This problem does not manifest itself in perl 5.30.0 (Windows 10, Strawberry Perl) or Perl v5.24.2.
Note: the problem manifests itself not only with $count++ but with any other access to content of the hash next to say "Person: $count"; -- post# 60653651
I would like to hear comments on this situation, what is the cause?
CAUSE: input data have eol in DOS form \r\n and when data processed in Linux chomp removes only \n leaving \r as part of the field name (used as hash key). Thanks goes to Shawn for pointing out the source of the issue.
SOLUTION: universal fix was implemented in form of snip_eol($arg) subroutine
use strict;
use warnings;
use feature 'say';
my $debug = 0;
say "
Perl: $^V
OS: $^O
-------------------
" if $debug;
my %hash;
my %seen;
my #header = split ',', <DATA>;
$header[2] = snip_eol($header[2]); # problem fix
while(<DATA>) {
next if /^\s*$/;
my $line = snip_eol($_); # problem fix
my %data;
#data{#header} = split ',',$line;
push #{$hash{person}}, \%data;
push #{$hash{Position}{$data{Position}}}, "$data{First} $data{Last}";
if( ! $seen{$data{Position}} ) {
$seen{$data{Position}} = 1;
push #{$hash{Role}}, $data{Position};
}
}
#say Dumper($hash{Position});
my $count = 0;
for my $person ( #{$hash{person}} ) {
$count++;
say "-> Name: $person->{First} $person->{Last}";
say "-> Role: $person->{Position}\n";
}
say "---- Groups ----\n";
while( my($p,$m) = each %{$hash{Position}} ) {
say "-> $p";
my $members = join(',',#{$m});
say "-> Members: $members\n";
}
say "---- Roles ----";
say '-> ' . join(', ',#{$hash{Role}});
sub snip_eol {
my $data = shift; # problem fix
#map{ say "$_ => " . ord } split '', $data if $debug;
$data =~ s/\r// if $^O eq 'linux';
chomp $data;
#map{ say "$_ => " . ord } split '', $data if $debug;
return $data;
}
__DATA__
First,Last,Position
John,Doe,Developer
Mary,Fox,Manager
Anna,Gulaby,Developer
I can replicate this behavior by (On linux) first converting the source file to have Windows-style \r\n line endings and then trying to run it. I thus suspect that in your testing of various versions you're using Windows sometimes, and a Linux/Unix other times, and not converting the file's line endings appropriately.
#chomp only removes a newline character (Well, the current value of $/ to be pedantic), so when used on a string with a Windows style line ending in it, it leaves the carriage return. The hash key is not "Position", it's "Position\r", which is not what the rest of your code uses.

to get output from variable

use strict;
use warnings;
$manifest=read_file("release.ms1");
print "$manifest\n";
my #new=split('\.',$manifest);
my %data=#new;
print "$data('vcs version')";
content of the release.ms1
vcs.version:12312321
vcs.path:CiscoMain/IT/GIS/trunk
Error:
vcs.version:12312321
vcs.path:CiscoMain/IT/GIS/trunk
vcsversion:12312321
vcspath:CiscoMain/IT/GIS/trunk
Odd number of elements in hash assignment at ./script.pl line 33.
Use of uninitialized value in print at ./script.pl line 35.
I need output like :
version=12312321
path=CiscoMain/IT/GIS/trunk
Your split function is assigning:
$new[0] = 'vcs'
$new[1] = 'version:12312321\nvcs'
$new[2] = 'path:CiscoMain/IT/GIS/trunk'
When you assign a list to a hash, it has to have an even number of elements, since they're required to be alternating keys and values.
It looks like what you actually want to do is split $manifest on newlines and colons, and replace the dots in the keys with space.
my #new = split(/[.\n]/, #manifest;
my %data;
for (my $i = 0; $i < #new; $i += 2) {
my $key = $new[$i];
$key =~ s/\./ /g;
$data{$key} = $new[$i+1];
}
Finally, your syntax for accessing an element of the hash is wrong. It should be:
print $data{'vcs version'};
The hash key is surrounded with curly braces, not parentheses.

Use of uninitialized value but variables declared

use strict;
use warnings;
my $last_variable2= 'abc';
print "last var2 $last_variable2\n";
my #grouped;
while (<DATA>) {
my ($variable1,
$variable2,
$other_data) = split ',',$_,3;
if($variable2 ne 'abc'){
if( $variable2 ne $last_variable2){
print "\n\n";
print "'$variable2' doesn't equal '$last_variable2'\n";
my %HoA;
&process_data(#grouped_series);
#grouped = ();
}
}else{
print "Skipped this because it's the first\n";
}
push #grouped_series, $_;
$last_variable2 = $variable2;
}
When I run this code, I keep getting
Use of uninitialized value $last_variable2 in string ne at 1_1_correspondencer.pl line 32, <DATA> line 3.
Use of uninitialized value $variable2 in string ne at 1_1_correspondencer.pl line 33, <DATA> line 3.
Use of uninitialized value $last_variable2 in concatenation (.) or string at 1_1_correspondencer.pl line 36, <DATA> line 6.
But, I initialized both variables. Sorry, this is a naive question--I only just started using strict and warnings
When parsing your DATA, you don't verify that each of these variables is defined:
my ($variable1,
$variable2,
$other_data) = split ',',$_,3;
If there are no commas on a row, then $variable2 would be undefined which is later assigned to $last_variable2. Maybe add some data verification to take into account that case?
if (! defined $variable2) {
warn "missing variable2 definition: $_\n";
}
Without seeing your actual data, we can't really advise you more.

Use of uninitialized value \$price in concatenation (.) or string at ./11LIST02.pl line

SO I have this data set
The Lion King!
Tumbleweed Connection!Elton John!123.32
Photographs & Memories!Jim Croce!4.95
Heads & Tales!Harry Chapin!12.50
and this script which give me uninitialized errrors
#!/usr/bin/perl
use warnings;
use strict;
open( my $filehandle , "<", $ARGV[0]) || die $!;
my #lines = <$filehandle> ;
close($filehandle) ;
foreach (#lines) {
chop;
my ($album ,$artist,$price );
($album, $artist, $price) = (split(/!/));
print ("Album=$album Artist=$artist Price=$price\n");
}
Errors
casper_mint#casper-mint-dell ~/david_mendinets. $ ./11LIST02.pl FORMAT.DAT
Use of uninitialized value $price in concatenation (.) or string at ./11LIST02.pl line 13.
Album=The Lion King Artist= Price=
Album=Tumbleweed Connection Artist=Elton John Price=123.32
Album=Photographs & Memories Artist=Jim Croce Price=4.95
Album=Heads & Tales Artist=Harry Chapin Price=12.50
Use of uninitialized value $album in concatenation (.) or string at ./11LIST02.pl line 13.
Use of uninitialized value $artist in concatenation (.) or string at ./11LIST02.pl line 13.
Use of uninitialized value $price in concatenation (.) or string at ./11LIST02.pl line 13.
Album= Artist= Price=
So i fixed the script - but i am still getting one error.
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4
5 open( my $filehandle , "<", $ARGV[0]) || die $!;
6 my #lines = <$filehandle> ;
7 close($filehandle) ;
8
9 foreach (#lines) {
10 chop;
11 my $album ="";
12 my $artist ="";
13 my $price ="" ;
14 ($album, $artist, $price) = (split(/!/));
15 if (length $album) {
16 print ("Album=$album Artist=$artist Price=$price\n");
17 }
18 elsif (length $price) {
19 print ("Album=$album Artist=$artist Price=$price\n");
20 }
21 }
casper_mint#casper-mint-dell ~/david_mendinets. $ ./11LIST02.pl FORMAT.DAT
Use of uninitialized value $price in concatenation (.) or string at ./11LIST02.pl line 16.
Album=The Lion King Artist= Price=
Album=Tumbleweed Connection Artist=Elton John Price=123.32
Album=Photographs & Memories Artist=Jim Croce Price=4.95
Album=Heads & Tales Artist=Harry Chapin Price=12.50
casper_mint#casper-mint-dell ~/david_mendinets. $
I am having trouble getting rid of that last error - i do onto understand it
Try to restructure your code from lines 11-14 like this:
my ($album, $artist, $price) = (split(/!/));
$album ||= "";
$artist ||= "";
$price ||= "" ;
Split the values into the variables, and then assign a default value ("") if any of the values is undefined. That should fix you right up.
It seems that the line which get splitted has fewer than three elements, so default values could be assigned,
$_ //= "" for
my ($album, $artist, $price) = split /!/;
//= assigns empty string only when mentioned variables are undef, and not when they generally evaluate to false.

Use of uninitialized value in join or string at

use strict;
use warnings;
my $dir = "/";
my #old = `ls -1rtA $dir`;
#print #old;
my #variable declaration
while(1){
$oldlen = scalar #old;
#new = `ls -1rtA $dir`;
print #new;
$newlen = scalar #new;
if(#old ~~ #new)
{
}
else
{
$diff=$oldlen+1;
print "$diff \n";
print "$list \n";
#print "#new[$list] \n";
#$op=$new[$list];
print "$newlen \n";
#pop #core,$op;
print "#new[$diff..$newlen]";
print #core;
}
}
I am getting the following error:
Use of uninitialized value in join or string at print "#new[$diff..$newlen]";
What is causing this issue?
What does the error mean?
You have set $newlen to the number of elements in the array #new and then tried to access $new[$newlen]. The elements of #new are at indices 0 to $newlen - 1, so $new[$newlen] is beyond the end of the array. You get the warning because this evaluates to undef and is uninitialised.
You have the same problem with the start index of the slice, which should read
print "#new[$oldlen..$newlen-1]"