[Kc] Perl Noob

Andrew Moore amoore at mooresystems.com
Wed Sep 19 12:49:07 PDT 2007


On Wed, Sep 19, 2007 at 02:21:30PM -0500, Emmanuel Mejias wrote:
> That worked great, Andrew! Thanks! I added my sort and two extra lines so it
> does what it's suppose to do and  prints out envirnoment variables that I
> was asking it to print. here is my end result:
> 
> #!/usr/bin/perl -w
> 
> @key = qw(SHELL USER LANG HOSTNAME TERM HOME);
> 
>    foreach my $key (sort(keys %ENV)){
>        foreach $check (@key){
>            if ($key eq $check){
>               print "$key: $ENV{$key}\n";
>               }
>           }
> }

I'm glad it helped, Emmanuel. That version looks much better. I think
we can make some improvements, though, if you want. Here's your code
with line numbers to make it easier to talk about:

  1  #!/usr/bin/perl -w
  2
  3  @key = qw(SHELL USER LANG HOSTNAME TERM HOME);
  4
  5     foreach my $key (sort(keys %ENV)){
  6         foreach $check (@key){
  7             if ($key eq $check){
  8                print "$key: $ENV{$key}\n";
  9                }
 10            }


It looks like you want to print out the envionment variables SHELL,
USER, LANG, HOSTNAME, TERM, and HOME. No problem.

First, instead of using #!/usr/bin/perl -w at the top, let's get rid
of '-w' and do 'use warnings' instead. The difference is subtle, but
essentially we just want to enforce warnings on your code, not on all
modules you may have included (which for now is none). Also, let's add
'use strict', too. It helps make sure that we're declaring our
variables before we use them and avoiding some other common
errors. The first few lines look like this now:

#!/usr/bin/perl
use warnings;
use strict;

Because we're using strict now, we need to declare our list @key in
line 3. That line becomes:

my @key = qw(SHELL USER LANG HOSTNAME TERM HOME);

Now, in line 5 you walk through each of the keys in the %ENV hash, and
then in line 6 we walk through @key to see if it's one that we
want. Maybe it makes more sense to walk through just the keys we want,
and print them out of %ENV. That makes the loop look more like:

   foreach my $key ( @key ) {
      print "$key: $ENV{$key}\n";
   }

This means that we don't have to run through the @key list for each
one of the keys of %ENV. It's more efficient, and maybe more
intuitive.

But wait! This is different from yours, because if you have an element
in @key but no corresponding key in the %ENV hash (like HOSTNAME for
me), it will now print out a warning like:

Use of uninitialized value in concatenation (.) or string at /tmp/env.pl line 8.

Hmm. I guess we need to make sure that that key exists in the %ENV
hash first.

   foreach my $key ( @key ) {
      if ( exists $ENV{$key} ) {
          print "$key: $ENV{$key}\n";
      }

This means that only the things in @key that are also keys in the %ENV
hash get printed out. It's quicker to check for existence in the hash
on each loop interation than it is to walk through the @key list on
each iteration. More importantly, though, it's also more intuitive (to
me) to loop over each thing that we want to print, see if there's
anything to print for it, and then print it than it is to walk over
the list of things that exist, see if we want to print each, and then
print it.

After all this, the script looks something more like:

#!/usr/bin/perl

use warnings;
use strict;

@key = qw(SHELL USER LANG HOSTNAME TERM HOME);

foreach my $key ( @key ) {
    if ( exists $ENV{$key} ) {
        print "$key: $ENV{$key}\n";
    }
}

I personally think it's better than it used to be.

I'm a little confused now by the fact that we have a variable named
@key and another variable named $key. Maybe we should rename one or
both of them. Maybe there are more changes... This could go on
forever!

Let me know if that helps, and what you get stuck on next!

-Andy




More information about the kc mailing list