Use of uninitialized value in join or string at - perl

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]"

Related

Perl :Not a HASH reference while creating nested hash from multi dimension arrays

I want to create a nested hash by reading values from multi dimention arrays which are separated by -> e.g.
Array 1: key1->key2->key3->value
Array 2: key1->key2->value
Array 3: key1->value
When key has value and sub keys as well e.g. key2 has value and another key key3 as well then get error "Not a HASH reference ".Seem it is overwriting previous hash and considering it array.
Help is appreciated. I have tried to debug and print the values of variables and output by using dumper module and see that it is ARRAY reference and not hash.
in order to repro, please create .txt files e.g. from 1 to 3.txt in any folder and have below content in these files 1.txt : /TEST-TAG = ABC->DEF->fma->GHI/ 2.txt:/*TEST-TAG = ABC->DEF->fma 3.txt:/*TEST-TAG = ABC->DEF and then have in perl script
#!/usr/bin/perl
use strict;
use warnings;
my #lines=`grep -R 'TEST-TAG =' <FOLDER where .txt files present>`;
my $hash;
#parse the lines which has pattern /\*TEST-TAG = ABC->DEF->fma->GHI\*/
foreach (#lines)
{
print "line is $_\n";
my($all_cat) = $_ =~ /\=(.*)\*\//;
print "all cat is $all_cat\n";
my($testname) = $_ =~ /\/.*\/(.*)\./;
print "testname is $testname\n";
if (!$all_cat eq "") {
$all_cat =~ s/ //g;
my #ts = split(',', $all_cat);
print "ts is #ts\n";
my $i;
foreach (#ts) {
my #allfeat = split('->',$_);
my $count = scalar #allfeat;
for ($i = 0; $i<$count; $i++) {
my #temparr = #allfeat[$i..$count-1];
print "temparr is #temparr\n";
push #temparr, $testname;
ToNestedHash($hash, #temparr);
}
}
}
}
sub ToNestedHash {
my $ref = \shift;
print "sandeep in ref $ref\n";
print "sandeep in ref", ref($ref), "\n";
my $h = $$ref;
print "sandeep h $h\n";
my $value = pop;
print "sandeep value is $value\n";
print "sandeep array is #_\n";
print "refrence", ref($h), "\n";
foreach my $i (#_) {
print " before INDEX $i\n";
print Dumper($ref);
$ref =\$$ref->{ $i };
print "after INDEX $i\n";
print Dumper($ref);
}
if (!isinlist(\#{$$ref},$value)) {
push #{$$ref}, $value;
}
return $h;
}
# If element exists in the list
sub isinlist {
my ($aref, $key) = ($_[0], $_[1]);
foreach my $elem (#$aref){
if ($elem eq $key) {
return 1;
}
}
return 0;
}
I get this output with debug prints
line is File.txt:/*TEST-TAG = ABC->DEF->fma->GHI*/
all cat is ABC->DEF->fma->GHI
testname is hmma_884_row_row_f16_f16
ts is ABC->DEF->fma->GHI
temparr is ABC DEF fma GHI
sandeep in ref REF(0x12a1048)
sandeep in refREF
sandeep h HASH(0x12a09a0)
sandeep value is hmma_884_row_row_f16_f16
sandeep array is ABC DEF fma GHI
refrenceHASH
REF
temparr is DEF fma GHI
sandeep in ref REF(0x12a1048)
sandeep in refREF
sandeep h HASH(0x12a09a0)
sandeep value is hmma_884_row_row_f16_f16
sandeep array is DEF fma GHI
refrenceHASH
REF
temparr is fma GHI
sandeep in ref REF(0x12a1048)
sandeep in refREF
sandeep h HASH(0x12a09a0)
sandeep value is hmma_884_row_row_f16_f16
sandeep array is fma GHI
refrenceHASH
Not a HASH reference at createjson.pl line 80.
problematic line is $ref =\$$ref->{$_} foreach (#_);
After sleeping on it, I realized where you were trying to go with this more. Your issue of concern is the fact that you're trying to use some hash values as both arrays and as hashes. There are two approaches to dealing with this. Detect and handle it, or avoid it. The avoid code is much cleaner, so I'll show that.
As I mentioned in my original answer, I'm not sure what you had in mind for the 'Dumper' lines, but Data::Dump is probably a useful replacement for what you were using, with less complication than the Data::Dumper module that I was thinking you were somehow managing to use. I also chose to still provide a replacement for your file name regex, as I still don't want to bother with a full path name.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dump;
my #lines = `grep -R 'TEST-TAG =' foo`;
my $hash;
$| = 1; # keep STDOUT and STDERR together
#parse the lines which has pattern /\*TEST-TAG = ABC->DEF->fma->GHI\*/
foreach (#lines) {
print "line is $_\n";
my($all_cat) = $_ =~ /\=(.*)\*\//;
print "all cat is $all_cat\n";
my($testname) = $_ =~ /(?:.*\/)?(.*?)\./;
print "testname is $testname\n";
if ($all_cat ne "") {
$all_cat =~ s/ //g;
my #ts = split(',', $all_cat);
print "ts is #ts\n";
my $i;
foreach (#ts) {
my #allfeat = split('->',$_);
my $count = scalar #allfeat;
for ($i = 0; $i<$count; $i++) {
my #temparr = #allfeat[$i..$count-1];
print "temparr is #temparr\n";
push #temparr, $testname;
ToNestedHash($hash, #temparr);
}
}
}
}
sub ToNestedHash {
my $ref = \shift;
print "sandeep in ref ";
dd $ref;
my $h = $$ref;
print "sandeep h ";
dd $h;
my $value = pop;
print "sandeep value is $value\n";
print "sandeep array is #_\n";
print "refrence", ref($h), "\n";
foreach my $i (#_) {
print " before INDEX $i\n";
dd $ref;
$ref =\$$ref->{ $i };
print "after INDEX $i\n";
dd $ref;
}
$ref =\$$ref->{ _ARRAY };
if (!isinlist(\#{$$ref},$value)) {
push #{$$ref}, $value;
}
return $h;
}
# If element exists in the list
sub isinlist {
my ($aref, $key) = ($_[0], $_[1]);
foreach my $elem (#$aref){
if ($elem eq $key) {
return 1;
}
}
return 0;
}

Perl Error: Argument isn't numeric in array or hash lookup

I was writing a simple program to match words to a regex pattern. But I keep receiving the error above. This is my code:
my #words = ("Ordinary", "order", "afford", "cordford", "'ORD airport'");
foreach my $index (#words) {
if ($words[$index] =~ m/ord/) {
print "match\n";
} else {print "no match\n";}
}
Error I received:
Argument "Ordinary" isn't numeric in array or hash lookup at test.pl line 6.
Argument "order" isn't numeric in array or hash lookup at test.pl line 6.
Argument "afford" isn't numeric in array or hash lookup at test.pl line 6.
Argument "cordford" isn't numeric in array or hash lookup at test.pl line 6.
Argument "'ORD airport'" isn't numeric in array or hash lookup at test.pl line 6.
no matchno matchno matchno matchno match
Can anyone explain to me what's causing the error and why?
This is the code that you show (improved a little)
my #words = ( 'Ordinary', 'order', 'afford', 'cordford', q{'ORD airport'} );
for my $index ( #words ) {
if ( $words[$index] =~ /ord/ ) {
print "match\n";
}
else {
print "no match\n";
}
}
}
This for loop will set $index to each value in the #words array. So, for instance, the first time the loop is executed $index will be set to Ordinary; the second time it will be set to order etc.
Naming it $index shows clearly that you expected it to contain all the indices for #words. You can do that, like this
for my $index ( 0 .. $#words ) { ... }
and your program will work fine if you make just that change. The output is
no match
match
match
match
no match
But you had the right idea from the start. Most often an array is just a list of values and the indices have no relevance. That applies to your case, and you can write
for my $word ( #words ) {
if ( $word =~ m/ord/ ) {
print "match\n";
}
else {
print "no match\n";
}
}
Or using Perl's default variable $_ it can be written
for ( #words ) {
if ( m/ord/ ) {
print "match\n";
}
else {
print "no match\n";
}
}
or even just
print /ord/ ? "match\n" : "no match\n" for #words;
Every example above is exactly equivalent and so produces identical output
The reason is your $index will produce the elements of an array not the index values.
It should be foreach my $index (0..$#words) now $index will produce the index of an array in every iteration.
use strict;
use warnings;
my #words = ("Ordinary", "order", "afford", "cordford", "'ORD airport'");
foreach my $index (0..$#words) {
if ($words[$index] =~ m/ord/) {
print "match\n";
}
else {print "no match\n";}
}
Or else. simply check the condition with $index.
use strict;
use warnings;
my #words = ("Ordinary", "order", "afford", "cordford", "'ORD airport'");
foreach my $index (#words) {
if ($index =~ m/ord/) {
print "match\n";
}
else {print "no match\n";}
}
This is array lookup
$words[$index];
If it was a hash it would be
$words{$index};
Arrays expect integer indexes but you're using strings that look nothing like integers.
If you are iterating over arrays in Perl you don't need the index..
#!/usr/bin/perl
use strict;
use warnings;
my #words = ("Ordinary", "order", "afford", "cordford", "'ORD airport'");
foreach my $word (#words) {
if($word =~ m/ord/) {
print "$word match\n";
} else {
print "$word no match\n";
}
}
Note. I've used foreach because you see it in more language you could also use for
You can also try something a little bit alternative, note this won't end but it's worth studying ie
#!/usr/bin/perl
use strict;
use warnings;
my #words = ("Ordinary", "order", "afford", "cordford", "'ORD airport'");
my $iterator = sub {
my $item = shift(#words);
push(#words, $item);
return $item;
};
while(my $item = $iterator->()) {
print("$item\n");
}
I do love Perl.

How to obtain value of Perl regex match variable with index stored in another variable?

I have a subroutine that takes as input the a position in a string, and should return the word found at that position. For example:
use warnings;
use strict;
my $num=2;
my $val=getMatch($num);
sub getMatch {
my ($num)=#_;
my $str='a b c';
$str=~ /(\S+)\s(\S+)/;
my $res;
eval "$res=\$$num";
return $res
}
But this gives error:
Use of uninitialized value $res in concatenation (.) or string at ./p.pl line 16.
(I am trying to return $i where i is a value stored in another variable..)
I'd do:
my $num=2;
my $val=getMatch($num);
say $val;
sub getMatch {
my ($num)=#_;
my $str='a b c';
my #res = $str =~ /(\S+)\s(\S+)/;
return $res[$num-1];
}
Output:
b
You could use the #+ and #- special variables, documented in perlvar, like this:
sub getMatch {
my ($num)=#_;
my $str='a b c';
$str=~ /(\S+)\s(\S+)/;
return substr( $str, $-[$num], $+[$num] - $-[$num] );
}
print getMatch(1), "\n";
print getMatch(2), "\n";
Or you could adjust your regex like this:
sub getMatch {
my $num = shift() - 1;
my $str='a b c';
$str=~ /(?:\S+\s){$num}(\S+)/;
return $1;
}
print getMatch(1), "\n";
print getMatch(2), "\n";
...which has the advantage of producing only a single capture group.
Another option is to just split on space:
sub getMatch {
my ($num)=#_;
my $str='a b c';
return ( split /\s/, $str )[$num-1];
}
print getMatch(1), "\n";
print getMatch(2), "\n";
...but that last solution is more permissive as to what it will match; it doesn't explicitly require two or more non-space items separated by a space. If 3 were passed in, it would return 'c'.
This last one produces results similar to the split version but using a regex. I'd probably prefer the split because it's more straightforward, but I provide this just for edification:
sub getMatch {
my ($num)=#_;
my $str='a b c';
return ( $str =~ m/(\S+)(?=\s|$)/g )[$num-1];
}
print getMatch(1), "\n";
print getMatch(2), "\n";

Argument is not numeric error while comparing hash values based on keys

#!/usr/bin/perl
use strict;
use Data::Dumper;
use warnings;
my #mdsum;
open (IN1,"$ARGV[0]") || die "counldn't open";
open (MYFILE, '>>md5sum-problem.txt');
open (IN2, "mdsumfile.txt");
my %knomexl=();
my %knomemdsum = ();
my #arrfile ;
my $tempkey ;
my $tempval ;
my #values ;
my $val;
my $i;
my #newarra;
my $testxl ;
my $testmdsum;
while(<IN1>){
next if /barcode/;
#arrfile = split('\t', $_);
$knomexl{$arrfile[0]} = $arrfile[2];
}
while(<IN2>){
chomp $_;
#newarra = split(/ {1,}/, $_);
$tempval = $newarra[0];
$tempkey = $newarra[1];
$tempkey=~ s/\t*$//g;
$tempval=~ s/\s*$//g;
$tempkey=~s/.tar.gz//g;
$knomemdsum{$tempkey} = $tempval;
}
#values = keys %knomexl;
foreach $i(#values){
$testxl = $knomexl{$values[$i]};
print $testxl."\n";
$testmdsum = $knomemdsum{$values[$i]};
print $testmdsum."\n";
if ( $testxl ne $testmdsum ) {
if ($testxl ne ""){
print MYFILE "Files hasving md5sum issue $i\n";
}
}
}
close (MYFILE);
I have two files one both having File name and Mdsum values and I need to check that which all file's md5sum values are not matching so I understand that in some case where Value and corresponding values will not be their and I want those cases only. Any work around on this code ? Please. This code is pretty simple but don't know why it's not working!! :( :(
#values = keys %knomexl;
foreach $i(#values){
#print Dumper $knomexl{$values[$i]};
$testxl = $knomexl{$i};
print $testxl."\n";
$testmdsum = $knomemdsum{$i};
print $testmdsum."\n";
$i is an element of #values because of the foreach, not an index, so you shouldn't use $values[$i].

Perl Array Values Access and Sum by each unique key

# my code as follows
use strict;
use FileHandle;
my #LISTS = ('incoming');
my $WORK ="c:\";
my $OUT ="c:\";
foreach my $list (#LISTS) {
my $INFILE = $WORK."test.dat";
my $OUTFILE = $OUT."TEST.dat";
while (<$input>) {
chomp;
my($f1,$f2,$f3,$f4,$f5,$f6,$f7) = split(/\|/);
push #sum, $f4,$f7;
}
}
while (#sum) {
my ($key,$value)= {shift#sum, shift#sum};
$hash{$key}=0;
$hash{$key} += $value;
}
while my $key (#sum) {
print $output2 sprintf("$key1\n");
# print $output2 sprintf("$key ===> $hash{$key}\n");
}
close($input);
close($output);
I am getting errors Unintialized error at addition (+) If I use 2nd print
I get HASH(0x19a69451) values if I use 1st Print.
I request you please correct me.
My output should be
unique Id ===> Total Revenue ($f4==>$f7)
This is wrong:
"c:\";
Perl reads that as a string starting with c:";\n.... Or in other words, it is a run away string. You need to write the last character as \\ to escape the \ and prevent it from escaping the subsequent " character
You probably want to use parens instead of braces:
my ($key, $value) = (shift #sum, shift #sum);
You would get that Unintialized error at addition (+) warning if the #sum array has an odd number of elements.
See also perltidy.
You should not enter the second while loop :
while my $key (#sum) {
because the previous one left the array #sum empty.
You could change to:
while (<$input>) {
chomp;
my #tmp = split(/\|/);
$hash{$tmp[3]} += $tmp[6];
}
print Dumper \%hash;