Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Reading a value from a hash using a variable for the key

18 views
Skip to first unread message

Eyal B.

unread,
Jan 20, 2011, 8:38:00 AM1/20/11
to begi...@perl.org
I'm writing a scripts that check the TTL of the ping and found the OS.
According the TTL - the script should let me know which OS it is :
Linux/ Windows or Unix (Hash table)

I'm getting an error on the line where I should use the TTL variable -
and take the right value from the hash (%list) :Use of uninitialized
value in print at D:\system\perl\os-rec\os-rec5_.pl line 24
, <HANDLE> line 3.

Any idea ?


#! C:\Perl\bin\perl -w
use strict;
use warnings;

my %list = (60,"linux",61,"linux",62,"linux",63,"linux",64,"linux",
65,"linux",125,"Windows",126,"Windows",127,"Windows",128,"Windows",
250,"Unix",251,"Unix",252,"Unix",253,"Unix",254,"Unix",255,"Unix",
256,"Unix",257,"Unix",258,"Unix",259,"Unix",260,"Unix");
my $path = "hosts.txt" ;
my $machine_IP ;
my $cmd ;

# read machines hosts names List from the txt file c:1.txt and take
the TTL data to th e variable: $line
open (MACHINES,$path) or die "Couldn't open file for writing";
while ($machine_IP = <MACHINES>)
{
chomp($machine_IP) ;
my $line ;
$cmd = "ping $machine_IP";
open(HANDLE,"$cmd|");
while ($line = <HANDLE>)
{
if("$line" =~ "TTL=")
{
$line =~ s/.*TTL=//;
print "TTL = $line\n";
print $list{"$line"} ;
# print "Machine $machine_IP is $list{$line}" ;
last; }
}
}
close HANDLE;
close MACHINES;

Shlomi Fish

unread,
Jan 20, 2011, 12:11:57 PM1/20/11
to begi...@perl.org, Eyal B.
Hi Eyal,

On Thursday 20 Jan 2011 15:38:00 Eyal B. wrote:
> I'm writing a scripts that check the TTL of the ping and found the OS.
> According the TTL - the script should let me know which OS it is :
> Linux/ Windows or Unix (Hash table)
>
> I'm getting an error on the line where I should use the TTL variable -
> and take the right value from the hash (%list) :Use of uninitialized
> value in print at D:\system\perl\os-rec\os-rec5_.pl line 24
> , <HANDLE> line 3.
>
> Any idea ?
>

First of all, you should use a CPAN module for Ping (maybe
http://search.cpan.org/dist/Net-Ping/ ). Otherwise, here are some comments on
your code.

>
> #! C:\Perl\bin\perl -w
> use strict;
> use warnings;

You shouldn't specify -w in the sha-bang. "use warnings;" (which you also
have) is better.

>
> my %list = (60,"linux",61,"linux",62,"linux",63,"linux",64,"linux",
> 65,"linux",125,"Windows",126,"Windows",127,"Windows",128,"Windows",
> 250,"Unix",251,"Unix",252,"Unix",253,"Unix",254,"Unix",255,"Unix",
> 256,"Unix",257,"Unix",258,"Unix",259,"Unix",260,"Unix");

It's not a list -it's a hash. And you should use the fat comma ("=>"), and use
some indentation.

> my $path = "hosts.txt" ;
> my $machine_IP ;
> my $cmd ;
>

Don't predeclare the variables. Declare them when needed.

> # read machines hosts names List from the txt file c:1.txt and take
> the TTL data to th e variable: $line
> open (MACHINES,$path) or die "Couldn't open file for writing";

Use three args open and don't use bareword file handles.

> while ($machine_IP = <MACHINES>)
> {
> chomp($machine_IP) ;
> my $line ;
> $cmd = "ping $machine_IP";
> open(HANDLE,"$cmd|");

You should use three-args open, lexical filehandles and "or die". Furthermore,
use $cmd is not needed here as you can interpolate directly from $cmd.

> while ($line = <HANDLE>)
> {
> if("$line" =~ "TTL=")

No need for wrapping $line in double quotes here as $line is a string.

> {
> $line =~ s/.*TTL=//;

> print "TTL = $line\n";
> print $list{"$line"} ;

You can do all that in one regex match.

if (my ($ttl) = $line =~ m{TTL=(\d+)})

> # print "Machine $machine_IP is $list{$line}"
;
> last; }
> }
> }
> close HANDLE;
> close MACHINES;

For more information see:

http://perl-begin.org/tutorials/bad-elements/

Regards,

Shlomi Fish

--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
Escape from GNU Autohell - http://www.shlomifish.org/open-
source/anti/autohell/

Chuck Norris can make the statement "This statement is false" a true one.

Please reply to list if it's a mailing list post - http://shlom.in/reply .

Erez Schatz

unread,
Jan 21, 2011, 12:50:22 AM1/21/11
to begi...@perl.org
On 20 January 2011 15:38, Eyal B. <ewin...@gmail.com> wrote:
> I'm writing a scripts that check the TTL of the ping and found the OS.
> According the TTL - the script should let me know which OS it is :
> Linux/ Windows or Unix (Hash table)
>
> I'm getting an error on the line where I should use the TTL variable -
> and take the right value from the hash (%list) :Use of uninitialized
> value in print at D:\system\perl\os-rec\os-rec5_.pl line 24
> , <HANDLE> line 3.
>
> Any idea ?
>                        if("$line" =~ "TTL=")
>                                        {
>                                $line =~ s/.*TTL=//;
>                                print "TTL = $line\n";
>                                print $list{"$line"} ;
>                                # print "Machine $machine_IP is $list{$line}" ;
>                                last;                                   }

Assuming a specific line is made of nothing but TTL=, then $line =~
s/.*TTL=//; will erase the line, leaving you with an empty
(uninitialized) $line variable.

A way to debug this will be to include a print $line just before the
substitution, so you could find what is happening in each stage of the
iteration.

--
Erez

La perfection soit atteinte non quand il n'ya plus rien à ajouter,
mais quand il n'ya plus rien à retrancher.

Shlomi Fish

unread,
Jan 21, 2011, 4:39:16 AM1/21/11
to Eyal B., begi...@perl.org
Hi Eyal,

I should note that your plain text message is mal-formatted. It's not clear
which parts were said by me, and which parts were said by you. Next time,
please configure your mailer (GMail.com?) to format the message as plaintext
and to use proper "> " quoting as needed by netiquette rules.

On Friday 21 Jan 2011 10:00:06 אייל ב. wrote:
> Hi Shlomi
> I tried to put this answer on the Google group, but didn't succeed. (Sent
> it but it didn't published)

It's not a Google group - it's a @perl.org-hosted mailing list. I don't know
why it wasn't published, but you can try E-mail postm...@perl.org about it.
I'm CCing the list in any case.

> I hope this is OK I'm sending it right here.

I guess. I'm CCing the list.

> BTW, I read your story and very likes that. It's good and very brave to
> share your self with others.

Which story?

> Looks like you are really dealing with your life.
>
> Back to Perl :
> Tried to implement your recommendations .... step by step .....


>
> #! C:\Perl\bin\perl

> use strict;
> use warnings;
>
> my %list =

> (60=>"linux",61=>"linux",62=>"linux",63=>"linux",64=>"linux",65=>"linux",12
> 5=>"Windows",126=>"Windows",127=>"Windows",128=>"Windows",250=>"Unix",251=>
> "Unix",252=>"Unix",253=>"Unix",254=>"Unix",255=>"Unix",
> 256=>"Unix",257=>"Unix",258=>"Unix",259=>"Unix",260=>"Unix");

Like I said you should reformat that. And since you have a lot of duplicacy
you can use something like:

my %ttls_to_os =
(
Linux => [60..65],
Windows => [125 .. 128],
Unix => [250 .. 260],
);

And then construct a TTL->OS mapping using
http://perldoc.perl.org/functions/map.html .

>
> my $path = "hosts.txt" ;
> # open (MACHINES,$path) or die "Couldn't open file for writing";
> open my $input_fh, "<", $path
> or die "Could not open '$path' - $!";
>
> # Shlomi, you wrote : "Use three args open and don't use bareword file
> handles..."
>
> # I'm asking : Trying to implement that (Though, didn't understand what is
> "bareword")....where do I indicate the MACHINES handle ?

A bareword is something like «MACHINES», i.e: starting with an uppercase
letter and without a "$" sigil in front. And you can do:

[code]
open my $machines_fh, '<', $path
or die "Could not open '$path' - $!";
[/code]

And then use the «$machines_fh» file handle instead of «MACHINES».

>
> my $machine_IP ;


> while ($machine_IP = <MACHINES>)
> {

This should be written as:

[code]
while (my $machine_ip = <$machines_fh>)
[/code]

> chomp($machine_IP) ;
> my $line ;
> my $cmd ;


> $cmd = "ping $machine_IP";
> open(HANDLE,"$cmd|");
>

> # Shlomi, you wrote : You should use three-args open, lexical filehandles
> and "or die".
> # I'm asking : Can you pls show me how should I write that ?

You can do:

[code]
open my $handle, "ping $machine_IP|"
or die "Could not open the ping process - $!";
[/code]

In this case, a three args open using '-|' won't work because it's not
implemented in Windows yet.

> # Furthermore, use $cmd is not needed here as you can interpolate directly
> from $cmd.
> # I didn't understand what that means.

See above.

>
> while ($line = <HANDLE>)
> {
> if("$line" =~ "TTL=")
>

> # No need for wrapping $line in double quotes here as $line is a string.
> # as mentioned above


>
>
> {
> $line =~ s/.*TTL=//;
> print "TTL = $line\n";
> print $list{$line} ;

> last; }
> # You can do all that in one regex match.
> # I didn't reach so far ... Is that
>
> # if (my ($ttl) = $line =~ m{TTL=(\d+)})
>

Yes, it's that.

> # print "Machine $machine_IP is $list{$line}" ;
>
>
> }
> }

> close HANDLE;
> close MACHINES;
>
> # Without make the changes about the File Handle -
> I still got the error : Use of uninitialized value within %list in print at
> C:\system\Perl\OS-recognize\os-rec5.1_.pl line 35, <HANDLE> line 4.
>

Maybe you have a missing TTL from your hash. Try using a debugger:

http://perl-begin.org/topics/debugging/

Regards,

Shlomi Fish

--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/

Apple Inc. is Evil - http://www.shlomifish.org/open-source/anti/apple/

Eyal B.

unread,
Jan 20, 2011, 4:26:31 PM1/20/11
to begi...@perl.org
Tried to implement your recommendations .... step by step .....

#! C:\Perl\bin\perl
use strict;
use warnings;

my %list = (60=>"linux",61=>"linux",62=>"linux",63=>"linux",
64=>"linux",65=>"linux",125=>"Windows",126=>"Windows",127=>"Windows",


128=>"Windows",250=>"Unix",251=>"Unix",252=>"Unix",253=>"Unix",
254=>"Unix",255=>"Unix", 256=>"Unix",257=>"Unix",258=>"Unix",

259=>"Unix",260=>"Unix");

my $path = "hosts.txt" ;


# open (MACHINES,$path) or die "Couldn't open file for writing";
open my $input_fh, "<", $path
or die "Could not open '$path' - $!";

# Shlomi, you wrote : "Use three args open and don't use bareword file
handles..."

# I'm asking : Trying to implement that (Though, didn't understand
what is "bareword")....where do I indicate the MACHINES handle ?

my $machine_IP ;


while ($machine_IP = <MACHINES>)
{
chomp($machine_IP) ;
my $line ;

my $cmd ;


$cmd = "ping $machine_IP";
open(HANDLE,"$cmd|");

# Shlomi, you wrote : You should use three-args open, lexical


filehandles and "or die".

# I'm asking : Can you pls show me how should I write that ?

# Furthermore, use $cmd is not needed here as you can interpolate
directly from $cmd.


# I didn't understand what that means.

while ($line = <HANDLE>)


{
if("$line" =~ "TTL=")

# No need for wrapping $line in double quotes here as $line is a
string.
# as mentioned above


{
$line =~ s/.*TTL=//;
print "TTL = $line\n";
print $list{$line} ;

last; }
# You can do all that in one regex match.
# I didn't reach so far ... Is that

# if (my ($ttl) = $line =~ m{TTL=(\d+)})

# print "Machine $machine_IP is
$list{$line}" ;


}
}
close HANDLE;
close MACHINES;

# Without make the changes about the File Handle -
I still got the error : Use of uninitialized value within %list in
print at C:\system\Perl\OS-recognize\os-rec5.1_.pl line 35, <HANDLE>
line 4.

Thanks, Shlomi,

Eyal.

Eyal B.

unread,
Jan 21, 2011, 5:48:45 AM1/21/11
to begi...@perl.org
On Jan 21, 7:50 am, moonb...@gmail.com (Erez Schatz) wrote:

Hi Erez
print "TTL = $line\n"; Does give me the right value ! (I.e TTL = 125)
Also print $list{125} ; return the right value
But this is not working : print $list{$line} ;
What can happen for the variable ?

Rob Dixon

unread,
Jan 21, 2011, 9:30:18 AM1/21/11
to begi...@perl.org
On 21/01/2011 05:50, Erez Schatz wrote:
> On 20 January 2011 15:38, Eyal B.<ewin...@gmail.com> wrote:
>>
>> I'm getting an error on the line where I should use the TTL variable -
>> and take the right value from the hash (%list) :Use of uninitialized
>> value in print at D:\system\perl\os-rec\os-rec5_.pl line 24
>> ,<HANDLE> line 3.
>>
>> Any idea ?
>> if("$line" =~ "TTL=")
>> {
>> $line =~ s/.*TTL=//;
>> print "TTL = $line\n";
>> print $list{"$line"} ;
>> # print "Machine $machine_IP is $list{$line}" ;
>> last; }
>
> Assuming a specific line is made of nothing but TTL=, then $line =~
> s/.*TTL=//; will erase the line, leaving you with an empty
> (uninitialized) $line variable.

No it won't, it will leave $line containing a null (zero-length) string.
There is no way to change a string value to uninitialized (undef) by
deleting characters from it.

- Rob

Eyal B.

unread,
Jan 21, 2011, 4:42:53 PM1/21/11
to begi...@perl.org

ok. So why on print "TTL = $line\n"; I do get TTL = 125, if it's
undefined ?
Thanks, Rob, for your answer.....

Shlomi Fish

unread,
Jan 24, 2011, 4:05:09 AM1/24/11
to Eyal B, begi...@perl.org
Hi Eyal,

On Friday 21 Jan 2011 15:55:58 אייל ב. wrote:
> Hi Shlomi, Again.
> I'm sorry for keep sending you mails (It's because my answers to the
> to the group still doesn't work and I sent a complaint to
> postm...@perl.org)
>
> I hope now when I use a plain text message, it will be more understandable.
> (BTW, now it will use the ">" ? I really not have much experience in
> netiquette rules)

See:

* http://en.wikipedia.org/wiki/Posting_style

* http://www.caliburn.nl/topposting.html

[snipped personal stuff]

> Back to Perl, and to my script.
> Because there are many things to understand, I want to focus on my
> major problem why, following the variable I took from the Regular Ex.:
> $list.
> I don't know why this is working : print $list{125} ;
> But this ain't working : print $list{$line} ; while there is 125 on the
> %line. What can be the difference. (I tried chomp) ?
> I tried to debug, I still can't understand why it's doesn't work !

What does x $line and x \%list say inside the debugger.

>
> (BTW, I understood the bareword issue, and implement it , according to
> your recommendations. Got a new errors :
> Global symbol "$machine_IP" requires explicit package name at
> C:\system\Perl\OS- recognize\os-rec5.01_.pl line 14.
> Global symbol "$machine_IP" requires explicit package name at
> C:\system\Perl\OS- recognize\os-rec5.01_.pl line 15.
> Global symbol "$handle" requires explicit package name at
> C:\system\Perl\OS-reco gnize\os-rec5.01_.pl line 32.

That means you have not declared your variables. Read the thread here:

http://www.nntp.perl.org/group/perl.beginners/2007/07/msg93172.html

> Execution of C:\system\Perl\OS-recognize\os-rec5.01_.pl aborted due .....
>
> Here is the new code:
>
> [code]


>
> #! C:\Perl\bin\perl
> use strict;
> use warnings;
>
> my %list =
> (60=>"linux",61=>"linux",62=>"linux",63=>"linux",64=>"linux",65=>"linux",

> 125=>"Windows",126=>"Windows",127=>"Windows",128=>"Windows",

> 250=>"Unix",251=>"Unix",252=>"Unix",253=>"Unix",254=>"Unix",255=>"Unix",
> 256=>"Unix",257=>"Unix",258=>"Unix",259=>"Unix",260=>"Unix");
>

> my $path = "c:/system/Perl/hosts.txt" ;
> # read an IP List from the txt file c:/system/Perl/BSO2.txt and take


> the TTL data to the variable: $line

> open my $machines_fh, '<', $path
> or die "Could not open '$path' - $!";

> while (my $machine_ip = <$machines_fh>) {

Well, the indentation here is wrong, so it's hard to read. This seems like an
artefact of an indentation preserving mode while pasting without a special
reservation for preserving indentation.

Regards,

Shlomi Fish

--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/

Optimising Code for Speed - http://shlom.in/optimise

Eyal B.

unread,
Jan 22, 2011, 1:32:25 PM1/22/11
to begi...@perl.org
If so, how print "TTL = $line\n" does give me the right value ! (I
get TTL = 125 if ping to Windows machine.

Thanks, for your answers.

On Jan 21, 4:30 pm, rob.di...@gmx.com (Rob Dixon) wrote:

אייל ב.

unread,
Jan 22, 2011, 1:46:04 PM1/22/11
to beginners
Guys
You claim : s/.*TTL=//; will erase the line, leaving with an empty
(uninitialized) $line variable.
I want to ask :

If so, how print "TTL = $line\n" does give me the right value !
If it will leave $line containing a null (zero-length or undef) string
- how can I print it ?
(I get TTL = 125 if ping to Windows machine)


2011/1/21 Abuse Desk <ab...@perl.org>:
>
> On Jan 21, 2011, at 2:53, אייל ב. wrote:
>
> Google Groups might not be sending us the mail -- try posting directly to the list by emailing begi...@perl.org.
>
>  - ask
>
>> Hi
>> I'm sending a reply using the : http://groups.google.com/group/perl.beginners/browse_thread/thread/45594cc9ea0ae4b5/0e6e248cab1d1e62#0e6e248cab1d1e62
>>
>> Reply with my questions to the answers I got.
>> But nothing is published.
>>
>>
>> Thanks
>
>

Eyal B.

unread,
Jan 24, 2011, 3:29:11 AM1/24/11
to begi...@perl.org
On Jan 21, 11:42 pm, ewinst...@gmail.com ("Eyal B.") wrote:
> On Jan 21, 4:30 pm, rob.di...@gmx.com (Rob Dixon) wrote:
>
>
>
> > On 21/01/2011 05:50, Erez Schatz wrote:
>
> > > On 20 January 2011 15:38, Eyal B.<ewinst...@gmail.com>  wrote:
>
> > >> I'm getting an error on the line where I should use the TTL variable -
> > >> and take the right value from the hash (%list) :Use of uninitialized
> > >> value in print at D:\system\perl\os-rec\os-rec5_.pl line 24
> > >> ,<HANDLE>  line 3.
>
> > >> Any idea ?
> > >>                         if("$line" =~ "TTL=")
> > >>                                         {
> > >>                                 $line =~ s/.*TTL=//;
> > >>                                 print "TTL = $line\n";
> > >>                                 print $list{"$line"} ;
> > >>                                 # print "Machine $machine_IP is $list{$line}" ;
> > >>                                 last;                                   }
> I found the issue, and resolve it
> This regex clean unnecessary, extra digits: $line =~/.*TTL=\s*(\S+)\s*$/;
0 new messages