Hi,
I appreciate that this is off-topic and wholly understand if I don't get an answer, although one would really appreciate it if I do get an answer :)
Basically to improve my perl scripting, I've given myself a challenge where I would like to order the users in the passwd file by uid, I could do this in another language but I'm focused on improving my perl scripting. The script I've written so far is below, I've managed to figure out hashes and have read in the file and created a hash of hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone please help me to finish this off? I'm trying to avoid using perl modules as I want to improve my scripting ability.
#!/usr/bin/perl -w
use strict;
my ( $login, $p, $uid, $gid, $gecos, $dir, $s ); my $k; my $v; my $key; my $ip; my $value; my @sorted=();
my @uid=();
my %HoH = ();
my $file='/etc/passwd';
open( PASSWD, "< $file" ) or die "Can't open $file : $!";
while( <PASSWD> ) { ( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );
$HoH{ $login }{ 'login' } = $login; $HoH{ $login }{ 'p' } = $p; $HoH{ $login }{ 'uid' } = $uid; $HoH{ $login }{ 'gid' } = $gid; $HoH{ $login }{ 'gecos' } = $gecos; $HoH{ $login }{ 'dir' } = $dir; $HoH{ $login }{ 's' } = $s; #print "$login\n"; }
close PASSWD;
#while (($k,$v) = each %HoH) { # print "While Loop: $k\n"; #}
#foreach $ip (keys %HoH) { # print "First For: $ip\n"; # while (($key, $value) = each %{ $HoH{$ip} } ) { # print "$key = $value \n"; # } # print "\n"; #}
#while ( ($k, $v) = each %HoH ) { # print "$k: \n"; # while ( ($key, $value) = each %$v ) { # print "$key=$value "; # } # print "\n"; #}
#for $k ( sort keys %HoH ) { # print "$k: "; # for $v ( sort keys %{ $HoH{$k} } ) { # print "$v=$HoH{$k}{$v} "; # } # print "\n"; #}
#@sorted = sort { $HoH{$a} cmp $HoH{$b} } keys %HoH; #print "@sorted\n";
#foreach my $sorted ( sort { $HoH{$a}->{"uid"} cmp $HoH{$b}->{"uid"} } keys %HoH) foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH) { print STDOUT "$HoH{$sorted}\n" }
Thank in advance for any help.
Dan
Hi,
I appreciate that this is off-topic and wholly understand if I don't get an answer, although one would really appreciate it if I do get an answer :)
Basically to improve my perl scripting, I've given myself a challenge where I would like to order the users in the passwd file by uid, I could do this in another language but I'm focused on improving my perl scripting. The script I've written so far is below, I've managed to figure out hashes and have read in the file and created a hash of hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone please help me to finish this off? I'm trying to avoid using perl modules as I want to improve my scripting ability.
#!/usr/bin/perl -w
use strict;
my ( $login, $p, $uid, $gid, $gecos, $dir, $s ); my $k; my $v; my $key; my $ip; my $value; my @sorted=();
my @uid=();
my %HoH = ();
my $file='/etc/passwd';
open( PASSWD, "< $file" ) or die "Can't open $file : $!";
while( <PASSWD> ) { ( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );
$HoH{ $login }{ 'login' } = $login; $HoH{ $login }{ 'p' } = $p; $HoH{ $login }{ 'uid' } = $uid; $HoH{ $login }{ 'gid' } = $gid; $HoH{ $login }{ 'gecos' } = $gecos; $HoH{ $login }{ 'dir' } = $dir; $HoH{ $login }{ 's' } = $s; #print "$login\n"; }
close PASSWD;
#while (($k,$v) = each %HoH) { # print "While Loop: $k\n"; #}
#foreach $ip (keys %HoH) { # print "First For: $ip\n"; # while (($key, $value) = each %{ $HoH{$ip} } ) { # print "$key = $value \n"; # } # print "\n"; #}
#while ( ($k, $v) = each %HoH ) { # print "$k: \n"; # while ( ($key, $value) = each %$v ) { # print "$key=$value "; # } # print "\n"; #}
#for $k ( sort keys %HoH ) { # print "$k: "; # for $v ( sort keys %{ $HoH{$k} } ) { # print "$v=$HoH{$k}{$v} "; # } # print "\n"; #}
#@sorted = sort { $HoH{$a} cmp $HoH{$b} } keys %HoH; #print "@sorted\n";
#foreach my $sorted ( sort { $HoH{$a}->{"uid"} cmp $HoH{$b}->{"uid"} } keys %HoH) foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH) { print STDOUT "$HoH{$sorted}\n" }
Thank in advance for any help.
Dan
On Wed, Apr 21, 2010 at 10:20:27 +0100, Dan Track dan.track@gmail.com wrote:
Basically to improve my perl scripting, I've given myself a challenge where I would like to order the users in the passwd file by uid, I could do this in another language but I'm focused on improving my perl scripting. The script I've written so far is below, I've managed to figure out hashes and have read in the file and created a hash of hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone please help me to finish this off? I'm trying to avoid using perl modules as I want to improve my scripting ability.
It looks like you are doing string comparisons on the uid. I think you might want to try <=> instead of cmp.
On Wed, Apr 21, 2010 at 09:21:30AM +0100, Dan Track wrote:
hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone
[snip]
foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH)
cmp is a string comparison. You probably want to sort numerically on the uid. So replace 'cmp' with '<=>'
Perhaps that is the problem?
On Wed, Apr 21, 2010 at 1:30 PM, Norman Gaywood ngaywood@une.edu.au wrote:
On Wed, Apr 21, 2010 at 09:21:30AM +0100, Dan Track wrote:
hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone
[snip]
foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH)
cmp is a string comparison. You probably want to sort numerically on the uid. So replace 'cmp' with '<=>'
Perhaps that is the problem?
Hi,
Thanks for that, although it didn't work at least I think so.
foreach my $sorted ( sort { $HoH{$a}->{"uid"} <=> $HoH{$b}->{"uid"} } keys %HoH) { print STDOUT "$HoH{$sorted}\n" }
and all I get out is:
perl sort.pl HASH(0x89de3d0) HASH(0x8a05d40) HASH(0x8a05dd0) HASH(0x8a05e60) HASH(0x8a05ef0) HASH(0x8a05f80) HASH(0x8a06010) HASH(0x8a060a0) HASH(0x8a06130) HASH(0x8a061c0) HASH(0x8a06250) HASH(0x8a062e0) HASH(0x8a06370) HASH(0x8a06400) HASH(0x8a0fd70) HASH(0x8a0fe90) HASH(0x8a101f0) HASH(0x8a10040) HASH(0x8a10790) HASH(0x8a100d0) HASH(0x8a10160) HASH(0x8a10700) HASH(0x8a10430) HASH(0x8a0ff20) HASH(0x8a10550) HASH(0x8a10310) HASH(0x8a0ffb0) HASH(0x8a103a0) HASH(0x8a0fe00) HASH(0x8a104c0) HASH(0x8a105e0) HASH(0x8a10670) HASH(0x8a10280)
Any thoughts on this?
Thanks Dan
On Wed, Apr 21, 2010 at 04:12:06PM +0100, Dan Track wrote:
On Wed, Apr 21, 2010 at 1:30 PM, Norman Gaywood ngaywood@une.edu.au wrote:
On Wed, Apr 21, 2010 at 09:21:30AM +0100, Dan Track wrote:
hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone
[snip]
foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH)
cmp is a string comparison. You probably want to sort numerically on the uid. So replace 'cmp' with '<=>'
foreach my $sorted ( sort { $HoH{$a}->{"uid"} <=> $HoH{$b}->{"uid"} } keys %HoH) { print STDOUT "$HoH{$sorted}\n" }
and all I get out is:
perl sort.pl HASH(0x89de3d0) HASH(0x8a05d40)
[snip]
$HoH{$sorted} is a reference to a hash. $HoH{$a}{uid} (or in long hand $HoH{$a}->{"uid"}) should print out the uid numbers.
On 22 April 2010 01:26, Norman Gaywood ngaywood@une.edu.au wrote:
On Wed, Apr 21, 2010 at 04:12:06PM +0100, Dan Track wrote:
On Wed, Apr 21, 2010 at 1:30 PM, Norman Gaywood ngaywood@une.edu.au wrote:
On Wed, Apr 21, 2010 at 09:21:30AM +0100, Dan Track wrote:
hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone
[snip]
foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH)
cmp is a string comparison. You probably want to sort numerically on the uid. So replace 'cmp' with '<=>'
foreach my $sorted ( sort { $HoH{$a}->{"uid"} <=> $HoH{$b}->{"uid"} } keys %HoH) { print STDOUT "$HoH{$sorted}\n" }
and all I get out is:
perl sort.pl HASH(0x89de3d0) HASH(0x8a05d40)
[snip]
$HoH{$sorted} is a reference to a hash. $HoH{$a}{uid} (or in long hand $HoH{$a}->{"uid"}) should print out the uid numbers.
That should be $HoH{$sorted}{uid}
google is perl's best friend, google, 'perl sort arrays' ...
good luck, jackc...
On 04/21/2010 01:21 AM, Dan Track wrote:
Hi,
I appreciate that this is off-topic and wholly understand if I don't get an answer, although one would really appreciate it if I do get an answer :)
Basically to improve my perl scripting, I've given myself a challenge where I would like to order the users in the passwd file by uid, I could do this in another language but I'm focused on improving my perl scripting. The script I've written so far is below, I've managed to figure out hashes and have read in the file and created a hash of hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone please help me to finish this off? I'm trying to avoid using perl modules as I want to improve my scripting ability.
#!/usr/bin/perl -w
use strict;
my ( $login, $p, $uid, $gid, $gecos, $dir, $s ); my $k; my $v; my $key; my $ip; my $value; my @sorted=();
my @uid=();
my %HoH = ();
my $file='/etc/passwd';
open( PASSWD, "< $file" ) or die "Can't open $file : $!";
while(<PASSWD> ) { ( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );
$HoH{ $login }{ 'login' } = $login; $HoH{ $login }{ 'p' } = $p; $HoH{ $login }{ 'uid' } = $uid; $HoH{ $login }{ 'gid' } = $gid; $HoH{ $login }{ 'gecos' } = $gecos; $HoH{ $login }{ 'dir' } = $dir; $HoH{ $login }{ 's' } = $s; #print "$login\n"; } close PASSWD;
#while (($k,$v) = each %HoH) { # print "While Loop: $k\n"; #}
#foreach $ip (keys %HoH) { # print "First For: $ip\n"; # while (($key, $value) = each %{ $HoH{$ip} } ) { # print "$key = $value \n"; # } # print "\n"; #}
#while ( ($k, $v) = each %HoH ) { # print "$k: \n"; # while ( ($key, $value) = each %$v ) { # print "$key=$value "; # } # print "\n"; #}
#for $k ( sort keys %HoH ) { # print "$k: "; # for $v ( sort keys %{ $HoH{$k} } ) { # print "$v=$HoH{$k}{$v} "; # } # print "\n"; #}
#@sorted = sort { $HoH{$a} cmp $HoH{$b} } keys %HoH; #print "@sorted\n";
#foreach my $sorted ( sort { $HoH{$a}->{"uid"} cmp $HoH{$b}->{"uid"} } keys %HoH) foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH) { print STDOUT "$HoH{$sorted}\n" }
Thank in advance for any help.
Dan
On Wed, Apr 21, 2010 at 4:41 PM, Norman Gaywood ngaywood@une.edu.au wrote:
On 22 April 2010 01:26, Norman Gaywood ngaywood@une.edu.au wrote:
On Wed, Apr 21, 2010 at 04:12:06PM +0100, Dan Track wrote:
On Wed, Apr 21, 2010 at 1:30 PM, Norman Gaywood ngaywood@une.edu.au wrote:
On Wed, Apr 21, 2010 at 09:21:30AM +0100, Dan Track wrote:
hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone
[snip]
foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH)
cmp is a string comparison. You probably want to sort numerically on the uid. So replace 'cmp' with '<=>'
foreach my $sorted ( sort { $HoH{$a}->{"uid"} <=> $HoH{$b}->{"uid"} } keys %HoH) { print STDOUT "$HoH{$sorted}\n" }
and all I get out is:
perl sort.pl HASH(0x89de3d0) HASH(0x8a05d40)
[snip]
$HoH{$sorted} is a reference to a hash. $HoH{$a}{uid} (or in long hand $HoH{$a}->{"uid"}) should print out the uid numbers.
That should be $HoH{$sorted}{uid}
--
Fantastic, you're a star :)
One last point how can I print all the associated deatils attached to that uid i.e username, home dir etc and then cycle through for every uid and print the same information for each respective uid? The uid's need to be in order i.e something like
uid: 0, username: root etc... uid 50, username: mysql etc...
Many many thanks Dan
On Wed, Apr 21, 2010 at 4:21 AM, Dan Track dan.track@gmail.com wrote:
Hi,
Hey
I appreciate that this is off-topic and wholly understand if I don't get an answer, although one would really appreciate it if I do get an answer :)
Can you please mark as OT in the subject next time? That way anyone not interested in non-Fedora specific questions can easily filter off topic subjects out.
Basically to improve my perl scripting, I've given myself a challenge
where I would like to order the users in the passwd file by uid, I could do this in another language but I'm focused on improving my perl scripting. The script I've written so far is below, I've managed to figure out hashes and have read in the file and created a hash of hashes. It's after this that I'm stuck, I'm struggling to order the hash of hashes by uid and then print the ordered list out? Can someone please help me to finish this off? I'm trying to avoid using perl modules as I want to improve my scripting ability.
sure, I'll provide some tips.
#!/usr/bin/perl -w
-w is deprecated. use warnings; instead
use strict;
very good. always use strict;
my ( $login, $p, $uid, $gid, $gecos, $dir, $s ); my $k; my $v; my $key; my $ip; my $value; my @sorted=();
my @uid=();
this is a common error for ex-C/Java programmers, however in Perl there's no need to predefine variables. In fact, variables should be defined only in their smallest possible scope. This happens naturally if you define them as you use them.
my %HoH = ();
this is an ok name for learning, but in real scripts use a name that describes the contents, rather than the structure.
my $file='/etc/passwd';
open( PASSWD, "< $file" ) or die "Can't open $file : $!";
new method is 3-argument open, with lexically scoped filehandle: open( my $passwd, '<', $file ) or die "Can't open '$file': $!";
while( <PASSWD> ) {
this reads from the filehandle until eof, putting the results in $_. It is convenient to use $_, but it is usually advisable to create a new lexically scoped variable.
while( my $line = <$passwd> ) {
( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );
if these hadn't been pre-defined, this line would read as follows and would keep $login, $p, etc scoped to this while block
my ($login,$p,$uid,$gid,$gecos,$dir,$s) = split ':', $line;
$HoH{ $login }{ 'login' } = $login; $HoH{ $login }{ 'p' } = $p; $HoH{ $login }{ 'uid' } = $uid; $HoH{ $login }{ 'gid' } = $gid; $HoH{ $login }{ 'gecos' } = $gecos; $HoH{ $login }{ 'dir' } = $dir; $HoH{ $login }{ 's' } = $s; #print "$login\n"; }
This structure works well if you wanted to look up the characteristics of a given $login as hash access is great for lookups. but if you wanted to just reorder all of them, maybe an array of hashes would be better? just a thought.
close PASSWD;
#while (($k,$v) = each %HoH) { # print "While Loop: $k\n"; #}
#foreach $ip (keys %HoH) { # print "First For: $ip\n"; # while (($key, $value) = each %{ $HoH{$ip} } ) { # print "$key = $value \n"; # } # print "\n"; #}
#while ( ($k, $v) = each %HoH ) { # print "$k: \n"; # while ( ($key, $value) = each %$v ) { # print "$key=$value "; # } # print "\n"; #}
#for $k ( sort keys %HoH ) { # print "$k: "; # for $v ( sort keys %{ $HoH{$k} } ) { # print "$v=$HoH{$k}{$v} "; # } # print "\n"; #}
#@sorted = sort { $HoH{$a} cmp $HoH{$b} } keys %HoH; #print "@sorted\n";
#foreach my $sorted ( sort { $HoH{$a}->{"uid"} cmp $HoH{$b}->{"uid"} } keys %HoH) foreach my $sorted ( sort { $HoH->{$a}{uid} cmp $HoH->{$b}{uid} } keys %HoH) { print STDOUT "$HoH{$sorted}\n" }
as others have mentioned, to perform numeric comparisons use the "spaceship" operator: <=>
now, note how many hash accesses your loop performs. each time the sort wishes to compare two values, it must perform two nested hash lookups. As your Perl improves, you will learn how to make this sort more efficient - one common method is called the Schwartzian Transform. (No relation to Spaceballs)
Thank in advance for any help.http://fedoraproject.org/wiki/Mailing_list_guidelines
Hope my comments helped. Welcome to Perl.
On Wed, Apr 21, 2010 at 12:34 PM, Jake Peavy djstunks@gmail.com wrote:
On Wed, Apr 21, 2010 at 4:21 AM, Dan Track dan.track@gmail.com wrote:
Hi,
Hey
I appreciate that this is off-topic and wholly understand if I don't get an answer, although one would really appreciate it if I do get an answer :)
Can you please mark as OT in the subject next time? That way anyone not interested in non-Fedora specific questions can easily filter off topic subjects out.
LOL my bad....
On 21 April 2010 09:21, Dan Track dan.track@gmail.com wrote:
Hi,
I appreciate that this is off-topic and wholly understand if I don't get an answer, although one would really appreciate it if I do get an answer :)
Basically to improve my perl scripting, I've given myself a challenge where I would like to order the users in the passwd file by uid,
You've already got plenty of good advice in this thread, but I thought you might be interested in seeing just how short the program can be if you use a lot of Perl's features.
#!/usr/bin/perl
use strict; use warnings;
@ARGV = '/etc/passwd';
print sort { (split /:/, $a)[2] <=> (split /:/, $b)[2] } <>;
I probably wouldn't use something _quite_ this cryptic in production code.
Cheers,
Dave...
On Fri, Apr 23, 2010 at 09:06:45AM +0100, Dave Cross wrote:
I probably wouldn't use something _quite_ this cryptic in production code.
Oh, that wouldn't be a problem *IF* you commented the he11 out of it and bracketed the code with "DON'T CHANGE THIS IF YOU DON'T UNDERSTAND IT" comments.
IF tests showed this was much more efficient, that is. If it isn't, then cryptic isn't worth it.
Cheers, -- Dave Ihnat dihnat@dminet.com