3

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?
2
  • Not that I know of. For CSV files there are various tools to join the files on the given field, sort them, and split them back. You can probably emulate the same thing for general files: add a column, sort by it, remove the column. But it would be ugly. :) Commented Sep 16, 2016 at 22:29
  • 1
    You'll find similar questions (with answers) if you search the join tag... for the record, here's one way to do it: awk -F':' 'NR==FNR{z[$1]=$0;next}{print z[$1]}' /etc/shadow pw (where pw is your sorted /etc/passwd) Commented Sep 17, 2016 at 7:29

3 Answers 3

8

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-
2

There may be a more elegant way, but here's a two-step method:

for user in $(sort -n -t: -k3 /etc/passwd | cut -d: -f1)
do 
  grep ^${user}: /etc/shadow
done > /tmp/shadow.new

It reads /etc/shadow once for every entry in /etc/passwd.

1

I need sudo to read /etc/shadow on my machine:

sudo awk -F: 'NR==FNR {uid[$1]=$3; next} {print uid[$1], $0}' /etc/passwd /etc/shadow |
 sort -n |
 cut -d" " -f2-

The awk script prints the uid from the passwd file corresponding to the username in the shadow file, separated by a space. It's then sorted numerically and then the uid is dropped by the cut command.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .