Chad Kellerman wrote: > > Hello everyone, Hello,
> I think I am getting the hang of using perl, just rough around the > edges. I was hoping you guys can give me a hand. Here is my issue. > From what I understand using global variables such as my #variable; it > not the most "proper" way of coding. Lexical scoping was added to Perl5 in order to facilitate programming in the large. Perhaps MJD's article "Coping With Scoping" will help http://perl.plover.com/FAQs/ > I ran into a problem that I can't > seem to get around using it. (just because I am a little new at this > programming stuff) > > I have a text file that has fields separated by pipes. Like so > > ----------------------<snip of text file>---------------------------- > > #dir name|ip|hostname|back|port|chK|ver|mon|cl|db|pure|usr > /export6/home213/bob.work|192.168.123.23|bob.com|1|1|1|5|21,22|1|0|1|bob > /export5/home413/chuck.home|192.168.123.201|chuck.com|1|1|1|3|80|1|1|1|chuck >#/export9/home325/sally.home|192.168.123.56|sally.com|1|1|1|3|80,21|1|1|1|sally > /export1/home425/tom.home|192.168.123.100|tom.com|1|0|1|3|80,21|0|1|1|tom > The text file has about 1000 entries just like the ones above. > > Here is the script I wrote: > > ----------------------<snip of code>--------------------------------- > > #!/usr/bin/perl > use strict; > use warnings; > $|++; > > use FileHandle; > > my $msl_Host; > my %msl_Host; > my $serverList = "/usr/local/account/main-server.list"; > > &mslSplit($serverList); # pass the list into the subroutine. ^^^^^^^^^^^ ^^^^^^^^ You aren't passing a list but a single scalar. :-) > foreach my $key (keys %msl_Host) { > my $href = $msl_Host{$key}; > next if ($href->{'ignore_flag'} =~ "#"); ^^^^^^ This works because the binding operator (=~) converts the string to a regular expression: perldoc perlop [snip] Binding Operators [snip] If the right argument is an expression rather than a search pattern, substitution, or transliteration, it is interpreted as a search pattern at run time. This can be less efficient than an explicit search, because the pat tern must be compiled every time the expression is evalu ated. However it looks like you want the eq equality operator: next if $href->{'ignore_flag'} eq '#'; > print "$href->{'host_name'}\n"; You could use the %msl_Host variable directly for the two previous lines. next if $msl_Host{$key}->{'ignore_flag'} eq '#'; print "$msl_Host{$key}->{'host_name'}\n"; > } > > sub mslSplit { > my $msl = new FileHandle "@_", "r" || die $?; ^^^^ ^^ ^^ You are stringifying an array when you should be using the first element of that array ($_[0] instead of "@_".) You are using the higher precedence || which will not do what you want it to do here. You are using $? in the error message but file open errors are reported in $!. If you are using Perl 5.6 or newer you don't need the FileHandle module to get a lexically scoped file handle. # Perl 5.6 or newer open my $msl, '<', $_[0] or die "Cannot open $_[0]: $!"; # On older Perls using FileHandle my $msl = new FileHandle $_[0], 'r' or die "Cannot open $_[0]: $!"; > while (<$msl>) { > chomp; > my ($backup_dir, $host_ip, $host_name, $backup_flag,undef) = split(/\|/) ; ^^^^^^ perldoc -f split [snip] The LIMIT parameter can be used to split a line partially ($login, $passwd, $remainder) = split(/:/, $_, 3); When assigning to a list, if LIMIT is omitted, Perl supplies a LIMIT one larger than the number of variables in the list, to avoid unnecessary work. For the list above LIMIT would have been 4 by default. In time critical applications it behooves you not to split into more fields than you really need. So the undef at the end of your list is unnecessary. > next if $backup_dir =~ /^#directory name/; > my ($comment, undef, $group_dir, $host_dir) = split(/\// , > $backup_dir); > my $daily_server = substr($group_dir,0,length($group_dir)-2); Another way to do this. :-) (my $daily_server = $group_dir) =~ s/..$//; > my %hostEntry = ( > 'backup_dir' => $backup_dir, > 'host_ip' => $host_ip, > 'backup_flag' => $backup_flag, > 'group_dir' => $group_dir, > 'daily_server' => $daily_server, > 'host_dir' => $host_dir, > 'ignore_flag' => $comment, > 'host_name' => $host_name > ); > $msl_Host{$host_name} = \%hostEntry; You could just assign all of this directly: $msl_Host{$host_name} = { 'backup_dir' => $backup_dir, 'host_ip' => $host_ip, 'backup_flag' => $backup_flag, 'group_dir' => $group_dir, 'daily_server' => $daily_server, 'host_dir' => $host_dir, 'ignore_flag' => $comment, 'host_name' => $host_name }; > } > $msl->close; Because $msl is lexically scoped it will close when the variable goes out of scope at the end of the subroutine but it never hurts to be sure. :-) > } > > -------------------------</end of code>--------------------------------- > This works exactly the way I want it. I can change my print statement > in the foreach loop and print any importatn field that I want. Ther are > no additional fields I need. > > I was wondering what can I do to clean it up. (Maybe be more > efficient) I really don't like having: > > my $msl_Host; > my %msl_Host; > > declared like that. But I don't know how to rewrite it so I don't > have to declare it like that. I kind stumbled across getting this just > to work. Any help would be appreciated. For a relatively small program like this using file scoped variables is not a big deal. Some other ways to do it are: ############## pass a reference to a hash ############## my $serverList = '/usr/local/account/main-server.list'; mslSplit( $serverList, \my %msl_Host ); for my $key ( keys %msl_Host ) { ... print ... } sub mslSplit { my ( $filename, $hashref ) = @_; ... ... %$hashref = ( key => $value, etc... ); } ############## return a reference to a hash ############## my $serverList = '/usr/local/account/main-server.list'; my $hashref = mslSplit( $serverList ); for my $key ( keys %$hashref ) { ... print ... } sub mslSplit { my $filename = shift; ... ... return { key => $value, etc... }; } ############## return an actual hash (not as efficient) ############## my $serverList = '/usr/local/account/main-server.list'; my %msl_Host = mslSplit( $serverList ); for my $key ( keys %msl_Host ) { ... print ... } sub mslSplit { my ( $filename ) = @_; ... ... return ( key => $value, etc... ); } John -- use Perl; program fulfillment -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]