Saved has asked for the wisdom of the Perl Monks concerning the following question:

I need to verify there is no duplicate UIDs in the /etc/passwd file. My plan was to sort the file by the UID, and then check for lines with UID = to previous line. Is this the best way? I was trying this code:
#!/usr/bin/perl -w #<SortPW2.pl> /etc/passwd sort by UID $file="/etc/passwd"; my @array = do { local( @ARGV, $/ ) = $file ; <> } ; #my @array = ( #'555900:user:lee:0:23030', #'3520916:user:joe:0:20487', #'395284:user:richard:3:17557', #'807060:group:smith:0:20573', #'381940:home:kimble:1:625', #); my @sorted = map {$_->[0]} sort {$a->[1] <=> $b->[1] || $a->[1] cmp $b->[1]} map {[$_,(split':')[0]]} @array; print "$_\n" for @sorted;
The commented out code works, but the modification to source the array from /etc/passwd fails. Is it the line feeds? how would I remove them? Or is there a better way. All help appreciated. Thanx

Replies are listed 'Best First'.
Re: Sort passwd by UID
by moritz (Cardinal) on Apr 06, 2011 at 12:46 UTC
    Setting $/ to undef (via local) makes it read the whole file as a single string, and not line by line. Which is why your approach fails.
    My plan was to sort the file by the UID, and then check for lines with UID = to previous line. Is this the best way?

    Not necessarily. The common perl idiom for checking uniqueness is to iterate over all the values, and store the UID in a hash. If it existed before in the hash, it's not uniq. Consider:

    my %uids; while (my $line = <$filehandle>) { my $uid = # extract from $line; if ($uids{$uid)) { print "'$uid' is duplicate\n" } else { $uids{$uid} = 1; } }
      Thanx, worked gr8.
Re: Sort passwd by UID
by toolic (Bishop) on Apr 06, 2011 at 12:49 UTC
    You have slurped all your input lines into the 1st element of the @array variable. Here's how I would do it:
    use warnings; use strict; use File::Slurp; my $file = '/etc/passwd'; my @lines = read_file($file); chomp @lines; my @sorted = map {$_->[0]} sort {$a->[1] <=> $b->[1] || $a->[1] cmp $b->[1]} map {[$_,(split':')[0]]} @lines; print "$_\n" for @sorted;