Find duplicate UIDs in passwd

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.

unbound:x:1001:1001:Un Bound,,,:/home/unbound:/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


open(F, "</etc/passwd");
while (<F>) {
    @line = split(/:/, $_);
    $accounts{$line[2]} .= "$line[0] "; # build a hash, with uid as the key

for $uid ( keys %accounts ) {
    @usernames = split(/ /, $accounts{$uid});
    if ($#usernames > 0) {
        print "$uid @usernames\n";

Now that’s more like it :-)

6 Replies to “Find duplicate UIDs in passwd”

  1. Ah, I didn’t see that bit. Fine then. Here’s the relevant addition:

    cut -d: -f3 /etc/passwd | sort | uniq -d | sed ‘s/.*/:x:&:/’ | egrep -f – /etc/passwd | cut -d: -f1,3

    And if you want to avoid duplicates in the final output (like multiple instances of nsd, in your example):

    cut -d: -f3 /etc/passwd | sort | uniq -d | sed ‘s/.*/:x:&:/’ | egrep -f – /etc/passwd | cut -d: -f1,3 | sort -t: -k2 -n | uniq

    At this point I’d probably prefer perl too, but this is more fun. ;^)

  2. A solution in Python:

    accounts = {}
    with open('asfd.txt') as f1:
        for line in f1:
            (username, dont_care, uid, *dont_care2) = line.split(':')
            if uid in accounts:
                accounts[uid] = list()
    duplicateUIDs = {}
    for uid in accounts:
        if len(accounts[uid]) > 1:
            duplicateUIDs[uid] = set(accounts[uid]), len(accounts[uid])
    1. A similar python version was what I came up with too:

      #!/usr/bin/env python
      accounts = {}
      for u in file('/etc/passwd').readlines():
          (name, _, uid) = u.split(':')[0:3]
          nlist = accounts.get(uid, [])
          accounts[uid] = nlist
      for uid in [u for u in accounts if len(accounts[u]) > 1]:
          print uid, " ".join(accounts[uid])

      This one prints on my laptop:

      $ python
      0 root toor


Εισάγετε τα παρακάτω στοιχεία ή επιλέξτε ένα εικονίδιο για να συνδεθείτε:


Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Αποσύνδεση /  Αλλαγή )

Φωτογραφία Twitter

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Twitter. Αποσύνδεση /  Αλλαγή )

Φωτογραφία Facebook

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Facebook. Αποσύνδεση /  Αλλαγή )

Σύνδεση με %s

Αρέσει σε %d bloggers: