Home > Archive > PERL Beginners > July 2005 > defined on hash value does not work in my code :(
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
defined on hash value does not work in my code :(
|
|
|
| Apologies for posting the whole program but I can't see where I am
going wrong, I have tried several things to get the following line to
work, but it appears to be broken:-
$cts + 1 if not
defined($db{$months}{$days}{$computernam
es}{$next});
$cts is never incremented even if there is no defined key->value pair
for $db{$months}{$days}{$computernames}{$nex
t}.
I am new to perl and this is only my second program, I would appreciate
some advice from more experienced perl people.
Many Thanks
====== code follows ======
#!/usr/bin/perl
use strict 'vars';
my %db;
my %ip2computer;
my %suspectipmapping;
my %usernamebyhour;
my %datesortorder = (Jan => '1', Feb => '2', Mar => '3', Apr => '4',
May => '5', Jun => '6', Jul => '7',
Aug => '8', Sep => '9', Oct => '10', Nov => '11', Dec => '12', 1 =>
'13', 2 => '14', 3 => '15',
4 => '16', 5 => '17', 6 => '18', 7 => '19', 8 => '20', 9 => '21', 10
=> '22', 11 => '23', 12 => '24',
13 => '25', 14 => '26', 15 => '27', 16 => '28', 17 => '29', 18 =>
'30', 19 => '31', 20 => '32',
21 => '33', 22 => '34', 23 => '35', 24 => '36', 25 => '37', 26 =>
'38', 27 => '39', 28 => '40',
29 => '41', 30 => '42', 31 => '43', );
sub bydate {
$datesortorder{$a} <=> $datesortorder{$b}
};
while (<> ) {
if (/ ^(\w+)\s+(\w+)\s+(\d\d):(\d\d):(\d\d)\s+
.*\]\s+540\s+.*
User\sName:(\S+)\$.*Network\s+Address:
(?!172\.20\.\d+\.\d+|172\.21\.20\.\d+|172\.21\.24\.\d+|127\.\d+\.\d+\.\d+)
(\d+\.\d+\.\d+\.\d+).*$/ix) {
my $month = "$1";
my $day = "$2";
my $hour = "$3";
my $minute = "$4";
my $second = "$5";
my $computername = uc("$6");
my $netaddress = "$7";
$db{$month}{$day}{$computername}{$hour} = "$hour"; # capture
hours on for computer
if (defined($ip2computer{$month}{$day}{$hou
r}{$netaddress})
&& $ip2computer{$month}{$day}{$hour}{$netad
dress} ne
$computername) {
$suspectipmapping{$ip2computer{$month}{$
day}{$hour}{$netaddress}}
= 1;
$suspectipmapping{$computername} = 1;
}
else {
$ip2computer{$month}{$day}{$hour}{$netad
dress} = $computername;
}
}
if (/ ^(\w+)\s+(\w+)\s+(\d\d):(\d\d):(\d\d)\s+
.*\]\s+673\s+.*
User\s+Name:\s*(?!\S+\$\@)(\S+)\@.*Client\s+Address:
(?!172\.20\.\d+\.\d+|172\.21\.20\.\d+|172\.21\.24\.\d+|127\.\d+\.\d+\.\d+)
(\d+\.\d+\.\d+\.\d+).*$/ix) {
my $month = "$1";
my $day = "$2";
my $hour = "$3";
my $minute = "$4";
my $second = "$5";
my $username = lc("$6");
my $netaddress = "$7";
unless
($usernamebyhour{$month}{$day}{$hour}{$i
p2computer{$month}{$day}{$hour}{$netaddr
ess}}
=~ /($username)/i) {
$usernamebyhour{$month}{$day}{$hour}{$ip
2computer{$month}{$day}{$hour}{$netaddre
ss}}
..= "$username "
}
}
}
#print "Report for domain PCs that communicated with domain
controllers, along with
#users who logged onto those PCs at least once.\n\n";
foreach my $months (sort bydate keys %db) {
foreach my $days (sort bydate keys %{$db{$months}}) {
#print "\n$months $days\n";
foreach my $computernames (sort keys %{$db{$months}{$days}}) {
printf "%s,%s,%s,", ($months,$days,$computernames);
my @times1;
my @times2;
my @times3;
my @times4;
my @users;
foreach my $hours qw/00 01 02 03 04 05 06 07 08 09 10 11 12
13 14 15 16 17 18 19 20 21 22 23/ {
my $previous = sprintf("%0.2d\n", ($hours - 1)) unless
$hours eq "00";
my $next = sprintf("%0.2d\n", ($hours + 1)) unless
$hours eq "23";
my $cts = 1; # current time slot
@times1[$#times1 + 1] = sprintf "%s",
$db{$months}{$days}{$computernames}{$hou
rs}
if ($db{$months}{$days}{$computernames}{$ho
urs}
&& $cts == 1);
@times2[$#times2 + 1] = sprintf "%s",
$db{$months}{$days}{$computernames}{$hou
rs}
if ($db{$months}{$days}{$computernames}{$ho
urs}
&& $cts == 2);
@times3[$#times3 + 1] = sprintf "%s",
$db{$months}{$days}{$computernames}{$hou
rs}
if ($db{$months}{$days}{$computernames}{$ho
urs}
&& $cts == 3);
@times4[$#times4 + 1] = sprintf "%s",
$db{$months}{$days}{$computernames}{$hou
rs}
if ($db{$months}{$days}{$computernames}{$ho
urs}
&& $cts == 4);
### The following line does not appear to work
$cts + 1 if not
defined($db{$months}{$days}{$computernam
es}{$next});
@users[$#users + 1] = sprintf "%s",
$usernamebyhour{$months}{$days}{$hours}{
$computernames}
if
$usernamebyhour{$months}{$days}{$hours}{
$computernames};
};
printf "%s,%s,", @times1[0,$#times1];
printf "%s,%s,", @times2[0,$#times2];
printf "%s,%s,", @times3[0,$#times3];
printf "%s,%s,", @times4[0,$#times4];
chop @users;
printf "%s,%s", @users[0,$#users];
print "\n";
}
#print "\nDaily total number of PCs: " .
keys(%{$db{$months}{$days}}) . "\n";
}
}
| |
|
| saffy wrote:
> Apologies for posting the whole program but I can't see where I am
> going wrong, I have tried several things to get the following line to
> work, but it appears to be broken:-
>
> $cts + 1 if not
> defined($db{$months}{$days}{$computernam
es}{$next});
>
> $cts is never incremented even if there is no defined key->value pair
> for $db{$months}{$days}{$computernames}{$nex
t}.
That's because you're not actually incrementing $cts. Try:
$cts += 1 if not defined();
or
++$cts if not defined();
instead.
HTH
Chris.
>
> I am new to perl and this is only my second program, I would appreciate
> some advice from more experienced perl people.
>
> Many Thanks
>
>
> ====== code follows ======
>
> #!/usr/bin/perl
>
> use strict 'vars';
>
> my %db;
> my %ip2computer;
> my %suspectipmapping;
> my %usernamebyhour;
> my %datesortorder = (Jan => '1', Feb => '2', Mar => '3', Apr => '4',
> May => '5', Jun => '6', Jul => '7',
> Aug => '8', Sep => '9', Oct => '10', Nov => '11', Dec => '12', 1 =>
> '13', 2 => '14', 3 => '15',
> 4 => '16', 5 => '17', 6 => '18', 7 => '19', 8 => '20', 9 => '21', 10
> => '22', 11 => '23', 12 => '24',
> 13 => '25', 14 => '26', 15 => '27', 16 => '28', 17 => '29', 18 =>
> '30', 19 => '31', 20 => '32',
> 21 => '33', 22 => '34', 23 => '35', 24 => '36', 25 => '37', 26 =>
> '38', 27 => '39', 28 => '40',
> 29 => '41', 30 => '42', 31 => '43', );
>
> sub bydate {
> $datesortorder{$a} <=> $datesortorder{$b}
> };
>
> while (<> ) {
> if (/ ^(\w+)\s+(\w+)\s+(\d\d):(\d\d):(\d\d)\s+
.*\]\s+540\s+.*
> User\sName:(\S+)\$.*Network\s+Address:
>
> (?!172\.20\.\d+\.\d+|172\.21\.20\.\d+|172\.21\.24\.\d+|127\.\d+\.\d+\.\d+)
> (\d+\.\d+\.\d+\.\d+).*$/ix) {
> my $month = "$1";
> my $day = "$2";
> my $hour = "$3";
> my $minute = "$4";
> my $second = "$5";
> my $computername = uc("$6");
> my $netaddress = "$7";
> $db{$month}{$day}{$computername}{$hour} = "$hour"; # capture
> hours on for computer
> if (defined($ip2computer{$month}{$day}{$hou
r}{$netaddress})
> && $ip2computer{$month}{$day}{$hour}{$netad
dress} ne
> $computername) {
> $suspectipmapping{$ip2computer{$month}{$
day}{$hour}{$netaddress}}
> = 1;
> $suspectipmapping{$computername} = 1;
> }
> else {
> $ip2computer{$month}{$day}{$hour}{$netad
dress} = $computername;
> }
> }
> if (/ ^(\w+)\s+(\w+)\s+(\d\d):(\d\d):(\d\d)\s+
.*\]\s+673\s+.*
> User\s+Name:\s*(?!\S+\$\@)(\S+)\@.*Client\s+Address:
>
> (?!172\.20\.\d+\.\d+|172\.21\.20\.\d+|172\.21\.24\.\d+|127\.\d+\.\d+\.\d+)
> (\d+\.\d+\.\d+\.\d+).*$/ix) {
> my $month = "$1";
> my $day = "$2";
> my $hour = "$3";
> my $minute = "$4";
> my $second = "$5";
> my $username = lc("$6");
> my $netaddress = "$7";
> unless
> ($usernamebyhour{$month}{$day}{$hour}{$i
p2computer{$month}{$day}{$hour}{$netaddr
ess}}
> =~ /($username)/i) {
>
> $usernamebyhour{$month}{$day}{$hour}{$ip
2computer{$month}{$day}{$hour}{$netaddre
ss}}
> .= "$username "
> }
> }
> }
>
> #print "Report for domain PCs that communicated with domain
> controllers, along with
> #users who logged onto those PCs at least once.\n\n";
>
> foreach my $months (sort bydate keys %db) {
> foreach my $days (sort bydate keys %{$db{$months}}) {
> #print "\n$months $days\n";
> foreach my $computernames (sort keys %{$db{$months}{$days}}) {
> printf "%s,%s,%s,", ($months,$days,$computernames);
> my @times1;
> my @times2;
> my @times3;
> my @times4;
> my @users;
> foreach my $hours qw/00 01 02 03 04 05 06 07 08 09 10 11 12
> 13 14 15 16 17 18 19 20 21 22 23/ {
> my $previous = sprintf("%0.2d\n", ($hours - 1)) unless
> $hours eq "00";
> my $next = sprintf("%0.2d\n", ($hours + 1)) unless
> $hours eq "23";
> my $cts = 1; # current time slot
> @times1[$#times1 + 1] = sprintf "%s",
> $db{$months}{$days}{$computernames}{$hou
rs}
> if ($db{$months}{$days}{$computernames}{$ho
urs}
> && $cts == 1);
> @times2[$#times2 + 1] = sprintf "%s",
> $db{$months}{$days}{$computernames}{$hou
rs}
> if ($db{$months}{$days}{$computernames}{$ho
urs}
> && $cts == 2);
> @times3[$#times3 + 1] = sprintf "%s",
> $db{$months}{$days}{$computernames}{$hou
rs}
> if ($db{$months}{$days}{$computernames}{$ho
urs}
> && $cts == 3);
> @times4[$#times4 + 1] = sprintf "%s",
> $db{$months}{$days}{$computernames}{$hou
rs}
> if ($db{$months}{$days}{$computernames}{$ho
urs}
> && $cts == 4);
>
> ### The following line does not appear to work
> $cts + 1 if not
> defined($db{$months}{$days}{$computernam
es}{$next});
> @users[$#users + 1] = sprintf "%s",
> $usernamebyhour{$months}{$days}{$hours}{
$computernames}
> if
> $usernamebyhour{$months}{$days}{$hours}{
$computernames};
> };
> printf "%s,%s,", @times1[0,$#times1];
> printf "%s,%s,", @times2[0,$#times2];
> printf "%s,%s,", @times3[0,$#times3];
> printf "%s,%s,", @times4[0,$#times4];
> chop @users;
> printf "%s,%s", @users[0,$#users];
> print "\n";
> }
> #print "\nDaily total number of PCs: " .
> keys(%{$db{$months}{$days}}) . "\n";
> }
> }
>
| |
|
| Sorry, posted too early:-
I have corrected the error and some others, but I still have the
problem:-
Basically, the problem boils down to the following, in the code below:-
this line works:-
$times1[$#times1 + 1] = sprintf "%s",
$db{$months}{$days}{$computernames}{$hou
rs}
if ($db{$months}{$days}{$computernames}{$ho
urs}
&& $cts == 1);
but this one doesn't:-
$cts++ unless defined($db{$months}{$days}{$computernam
es}{$next})
using the debugger shows that $next has the correct value i.e. (when
$hour = 00, $next = 01) but for some reason
$db{$months}{$days}{$computernames}{$nex
t} does not appear to ever
contain a value, even when it should!!
This is probably a silly syntax error on my part or there is something
about nested hashes that I don't understand.
Please help.
Many thanks.
=== simplified code ====
my %db;
while (<> ) {
## populate %db e.g.:-
## $db{$month}{$day}{$computername}{$hour} = "$hour";
##
}
foreach my $months (sort keys %db) {
foreach my $days (sort keys %{$db{$months}}) {
foreach my $computernames (sort keys %{$db{$months}{$days}}) {
my $cts = 1; # current time slot
foreach my $hours qw/00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
15 16 17 18 19 20 21 22 23/ {
my $next = sprintf("%0.2d\n", ($hours + 1)) unless $hours eq
"23";
$times1[$#times1 + 1] = sprintf "%s",
$db{$months}{$days}{$computernames}{$hou
rs}
if ($db{$months}{$days}{$computernames}{$ho
urs}
&& $cts == 1);
$times2[$#times2 + 1] = sprintf "%s",
$db{$months}{$days}{$computernames}{$hou
rs}
if ($db{$months}{$days}{$computernames}{$ho
urs}
&& $cts == 2);
$cts++ unless
defined($db{$months}{$days}{$computernam
es}{$next});
}
}
}
}
Chris wrote:[color=darkred]
> saffy wrote:
>
> That's because you're not actually incrementing $cts. Try:
>
> $cts += 1 if not defined();
>
> or
>
> ++$cts if not defined();
>
> instead.
> HTH
> Chris.
>
| |
|
| saffy wrote:
> Sorry, posted too early:-
>
> I have corrected the error and some others, but I still have the
> problem:-
>
> Basically, the problem boils down to the following, in the code below:-
>
> this line works:-
> $times1[$#times1 + 1] = sprintf "%s",
> $db{$months}{$days}{$computernames}{$hou
rs}
> if ($db{$months}{$days}{$computernames}{$ho
urs}
> && $cts == 1);
>
> but this one doesn't:-
> $cts++ unless defined($db{$months}{$days}{$computernam
es}{$next})
It is working. It's just not doing what (I think) you're expecting. The
above only increments $cts when
$db{$months}{$days}{$computernames}{$nex
t} is *not* defined, but what I
think you what is to increment $cts when the hash *is* defined. Try
changing the unless to if and see if that helps.
> using the debugger shows that $next has the correct value i.e. (when
> $hour = 00, $next = 01) but for some reason
> $db{$months}{$days}{$computernames}{$nex
t} does not appear to ever
> contain a value, even when it should!!
>
> This is probably a silly syntax error on my part or there is something
> about nested hashes that I don't understand.
>
I doubt it as perl would warn you of any syntax errors. You are using
warnings, right?
| |
|
| Thanks Chris,
Have used warnings but that does not give me any useful info on what is
happening. I have tried changing the unless to if but that gives me
different (still incorrect) results.
In an effort to debug this, I have tried to simplfy the code to the
simplest level. The code below is a working demonstration of the
problem. When run it gives the following output:-
debug: current = 00 next = cts = 2
debug: current = 01 next = cts = 3
debug: current = 02 next = cts = 4
debug: current = 06 next = cts = 5
debug: current = 07 next = cts = 6
debug: current = 08 next = cts = 7
debug: current = 09 next = cts = 8
debug: current = 12 next = cts = 9
debug: current = 13 next = cts = 10
debug: current = 14 next = cts = 11
debug: current = 15 next = cts = 12
debug: current = 16 next = cts = 13
debug: current = 17 next = cts = 14
debug: current = 18 next = cts = 15
debug: current = 19 next = cts = 16
debug: current = 20 next = cts = 17
When i am expecting this output:-
debug: current = 00 next = 01 cts = 1
debug: current = 01 next = 02 cts = 1
debug: current = 02 next = cts = 2
debug: current = 06 next = 07 cts = 2
debug: current = 07 next = 08 cts = 2
debug: current = 08 next = 09 cts = 2
debug: current = 09 next = cts = 3
debug: current = 12 next = 13 cts = 3
debug: current = 13 next = 14 cts = 3
debug: current = 14 next = 15 cts = 3
debug: current = 15 next = 16 cts = 3
debug: current = 16 next = 17 cts = 3
debug: current = 17 next = 18 cts = 3
debug: current = 18 next = 19 cts = 3
debug: current = 19 next = 20 cts = 3
debug: current = 20 next = cts = 4
I am trying to capture the "on" time periods for a pc that is switched
on and off throughout a 24 hour period.
Below is the simplified code I am using to replicate the problem. Any
advice would be gratefully received, thank you.
==== working example ====
#!/usr/bin/perl
use strict;
#use warnings;
my %db;
# initialize db with fake data for testing
# %db{month}{day}{computer}{hour} = {hour}
$db{"Jul"}{"Mon"}{"COMP1"}{'00'} = '00';
$db{"Jul"}{"Mon"}{"COMP1"}{'01'} = '01';
$db{"Jul"}{"Mon"}{"COMP1"}{'02'} = '02';
$db{"Jul"}{"Mon"}{"COMP1"}{'06'} = '06';
$db{"Jul"}{"Mon"}{"COMP1"}{'07'} = '07';
$db{"Jul"}{"Mon"}{"COMP1"}{'08'} = '08';
$db{"Jul"}{"Mon"}{"COMP1"}{'09'} = '09';
$db{"Jul"}{"Mon"}{"COMP1"}{'12'} = '12';
$db{"Jul"}{"Mon"}{"COMP1"}{'13'} = '13';
$db{"Jul"}{"Mon"}{"COMP1"}{'14'} = '14';
$db{"Jul"}{"Mon"}{"COMP1"}{'15'} = '15';
$db{"Jul"}{"Mon"}{"COMP1"}{'16'} = '16';
$db{"Jul"}{"Mon"}{"COMP1"}{'17'} = '17';
$db{"Jul"}{"Mon"}{"COMP1"}{'18'} = '18';
$db{"Jul"}{"Mon"}{"COMP1"}{'19'} = '19';
$db{"Jul"}{"Mon"}{"COMP1"}{'20'} = '20';
# print out info
foreach my $months (sort keys %db) {
foreach my $days (sort keys %{$db{$months}}) {
foreach my $computernames (sort keys %{$db{$months}{$days}}) {
my $cts = 1; # current time slot
foreach my $hours qw/00 01 02 03 04 05 06 07 08 09 10 11 12
13 14 15 16 17 18 19 20 21 22 23/ {
my $next = sprintf("%0.2d\n", ($hours + 1)) unless
$hours eq "23";
next unless $db{$months}{$days}{$computernames}{$hou
rs};
# increment time slot if next value is non-existent
$cts++ unless
$db{$months}{$days}{$computernames}{$nex
t};
printf "debug: \tcurrent = %s",
$db{$months}{$days}{$computernames}{$hou
rs};
printf "\tnext = %s",
$db{$months}{$days}{$computernames}{$nex
t};
printf "\t cts = %s\n", $cts;
};
}
}
}
# ==== end of working example ====
Chris wrote:
> saffy wrote:
>
> It is working. It's just not doing what (I think) you're expecting. The
> above only increments $cts when
> $db{$months}{$days}{$computernames}{$nex
t} is *not* defined, but what I
> think you what is to increment $cts when the hash *is* defined. Try
> changing the unless to if and see if that helps.
>
> I doubt it as perl would warn you of any syntax errors. You are using
> warnings, right?
| |
|
| I am such a banana!
I was adding a \n to the end of the sprintf statement:-
my $next = sprintf("%0.2d\n", ($hours + 1)) unless
$hours eq "23";
removing the \n fixed the problem.
Thanks for you help anyway.
|
|
|
|
|