A friend recently told me of a small problem he was asked to resolve:
«Find all duplicate UIDs in your /etc/passwd file. Print them along with the associated usernames. You may use shell, perl or python».
My first, almost instant, response was the following
awk -F: '{print $1,$3}' /etc/passwd | \
sort | uniq -c | \
awk '{if ($1 > 1) {print $3, $2}}'
But using the passwd sample below, I found a bug.
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
unbound:x:1001:1001:Un Bound,,,:/home/unbound:/bin/bash
nsd:x:1002:1002:,,,:/home/nsd:/bin/bash
nsd:x:1002:1002:,,,:/home/nsd:/bin/bash
nsd:x:1002:1002:,,,:/home/nsd:/bin/bash
insd:x:1002:1002:,,,:/home/nsd:/bin/bash
It misses the «insd» username, because it only prints out lines that contain the same uid *and* username.
So my second attempt was using perl
#!/usr/bin/perl
open(F, "</etc/passwd");
while (<F>) {
@line = split(/:/, $_);
$accounts{$line[2]} .= "$line[0] "; # build a hash, with uid as the key
}
close(F);
for $uid ( keys %accounts ) {
@usernames = split(/ /, $accounts{$uid});
if ($#usernames > 0) {
print "$uid @usernames\n";
}
}
Now that’s more like it :-)