Shell – Two files with a common field – is it possible to sort one based on the other

awkcommand lineshellsorttext processing

Lets say I got two files with a common field. I want to sort the first one based on a field (eg. a numeric field) found in this file… but I want this re-ordering to apply to the other file as well – through the common field.

To take an example — completely grabbed out of thin air 😉 — lets take the /etc/passwd and /etc/shadow:

/etc/passwd:
(...)
sshd:x:124:65534::/var/run/sshd:/usr/sbin/nologin
sndiod:x:999:29::/var/lib/sndiod:/usr/sbin/nologin
dictd:x:125:135:Dictd Server,,,:/var/lib/dictd:/bin/false
postgres:x:126:136:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
(...)
/etc/shadow:
(...)
sshd:*:17055:0:99999:7:::
sndiod:!:17055::::::
dictd:*:17055:0:99999:7:::
postgres:*:17055:0:99999:7:::
(...)

Sorting /etc/passwd numerically on UID is easy enough:

sort -n -t: -k3 /etc/passwd > pw

Which with the lines above yields:

/etc/passwd:
(...)
sshd:x:124:65534::/var/run/sshd:/usr/sbin/nologin
dictd:x:125:135:Dictd Server,,,:/var/lib/dictd:/bin/false
postgres:x:126:136:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
sndiod:x:999:29::/var/lib/sndiod:/usr/sbin/nologin
(...)

However, /etc/shadow does not have a numeric UID-field I can sort after… It does however — like /etc/passwd — got a username-field…

So is there a way to re-order the lines in /etc/shadow so that the username-field had the same order as the username-field in the numerically sorted /etc/passwd?

  • Is there a command — sort or something similar — which can sort file A after some key in that file, and simultaneously sort file B on a common field shared by both files?
  • Alternatively, is there a suitable two-step-process — a command, a sed/AWK/Perl-script, or something — that can use the sorted file A to re-order file B after their common field?

Best Answer

Join the files, sort the combined file, and strip out the columns you don't want.

In this case, field 1 of /etc/passwd is to be joined with field 1 of /etc/shadow, with : as the field separator.

join -t : -1 1 -2 1 /etc/passwd /etc/shadow |
sort -t : -k 3,3n |
cut -d : -f 1,8-
Related Question