Re: Retunining hash values from subroutines
by bart (Canon) on Jun 20, 2013 at 10:51 UTC
|
There are a few things wrong with your approach.
- You return the hash when you match a line for a single user
Instead, put the return statement at the end of the sub.
- You replace the contents of the hash for each user
Instead, add a single entry in the hash for each user doing this:
$UID_PATH{$USER} = $UID[5];
For optimization you could decide to return the hash ref, \%UID_PATH instead of a flattened list, but then you'd have to fix the script to use a hashref instead ofa hash, everywhere. (In languages like PHP and Javascript, there is no difference between a hash ref (or a hash. (AKA "associative array" in PHP and "object" in Javascript) | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Retunining hash values from subroutines
by hbm (Hermit) on Jun 20, 2013 at 11:31 UTC
|
In addition to bart's comments, you define %UID_PATH three times:
- globally, which you don't use
- at the start of your sub
- within the while loop (the effect of which you will see when you move the 'return' out of the loop)
Keep only the second.
| [reply] [Watch: Dir/Any] |
Re: Retunining hash values from subroutines
by packetstormer (Monk) on Jun 20, 2013 at 11:33 UTC
|
You could be a bit cleaner still and not declare the %UID_PATH hash as many times. Also, as stated above, the reason you were getting one line is that your return value was within the while loop, meaning the only the last value would be returned. Moving it outside and cleaning up a little as below:
#!/usr/bin/perl
use strict;
my %ARR1 = uid();
foreach my $TAB (keys %ARR1) {
print "User --> $TAB, Value --> $ARR1{$TAB}\n";
}
sub uid {
my %UID_PATH;
open (FH1, "</etc/passwd") || die "Can't Open : $!";
while (<FH1>) {
my @UID = split (/:/, $_);
if ($UID[2] > 500) {
my $USER = "$UID[0]";
$UID_PATH{$USER} = "$UID[5]";
}
}
return %UID_PATH;
}
| [reply] [Watch: Dir/Any] [d/l] |
|
Thank you so very much gentlemen. You all are great :)
Mr Packetst thank you very much I think I almost had it before I even began this thread but I lost it because of the has format I used.
%UID_PATH = ("$USER" => "$UID[5]")
instead of
$UID_PATH{$USER} = "$UID[5]";
Even though my problem is solved I still like to know as to how I should write the hash like the fist instance with the arrow, if at all possible. Kindly note if I write it that way only one entry from the /etc/passwd is returned.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
# Declare your hash
my %hash;
# Add the values below to the hash
$hash{1} = "a";
$hash{2} = "b";
$hash{3} = "c";
print "Hash after adding values\n";
print Dumper \%hash;
# Reinitialise hash - removing all previously added values
%hash = ('1' => 'a');
print "Hash when reinitialised\n";
print Dumper \%hash;
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
%UID_PATH = ("$USER" => "$UID[5]")
creates a new hash, meaning that anything that existed before in %UID_PATH is wiped out. This syntax is OK to give initial values to a hash, but should not be used for anything else, expecially not for feeding new key/value pairs into the hash. For that, use the other syntax that you showed:
$UID{$USER}= $UID[5]
(or whatever it was exactly)...
BTW, I would recommend against using upper case letters for variable names, it is a pain in the neck to type them, although I must admit it is largely a matter of personal taste. The most common practice is to have lower case letters for variables and functions, Title Case for package names, UPPER CASE for constants (and, often files handles and dir handles).
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Retunining hash values from subroutines
by BillKSmith (Monsignor) on Jun 20, 2013 at 10:52 UTC
|
my %UID_PATH;
my %ARR1 = uid();
foreach my $TAB (keys %ARR1) {
print "User --> $TAB, Value --> $ARR1{$TAB}\n";
}
sub uid {
my %UID_PATH;
my %ARR2; #add
open (FH1, "</etc/passwd") || die "Can't Open : $!";
while (<FH1>) {
my %UID_PATH;
my @UID = split (/:/, $_);
if ($UID[2] > 500) {
my $USER = "$UID[0]";
%UID_PATH = ("$USER" => "$UID[5]");
#print "$USER --> $UID_PATH{$USER}\n";
####### return %UID_PATH;
$AAR2{$USER} = $UID_PATH; #add
}
}
return %AAR@;
}
| [reply] [Watch: Dir/Any] [d/l] |
Re: Retunining hash values from subroutines
by kcott (Archbishop) on Jun 20, 2013 at 21:21 UTC
|
G'day Bindo,
You seem to have your answer with respect to "... main rational here is to understand hash behavior in subs.". This is additional information, regarding your example code, which you may find useful.
Here's a much more succinct way to generate the output you want:
$ perl -Mstrict -Mwarnings -le '
while (my @pwent = getpwent()) {
next if $pwent[2] <= 500;
print join " --> ", @pwent[0,7];
}
'
...
ken --> /Users/ken
...
In addition to getpwent() (which iterates through all records), there's also getpwnam() (which returns a single record based on username), getpwuid() (which returns a single record based on numeric user ID) and other related functions.
While the online documentation (Fetching user and group info) lists these functions, it provides little in the way of details (return values are not even shown). For that, you can use:
perldoc -f getpwent
| [reply] [Watch: Dir/Any] [d/l] [select] |