0

Im trying to sort a small file with some entries containing two words but i want to sort this as one entry.

for example consider this small list

 peter barker painter
 carl baker cook
 joshua carpenter

These are all names and occupations. now say i want to use sort to sort these entries.

Problem is sort uses white spaces as fields so if i sort -k 1n i'll sort by first name

But i want to sort by full name and then have the option to sort by occupation aswell. As you can see some entires don't have a full name, joshua only have his first name and his occupation. So for him i want to sort only by first name but for the others full name.

Can this be achieved?

1

Assuming that it is only ever going to be the surname that is missing (and not the first name) and that the words in the file does not include spaces (which would make it extremely difficult), first get the data into tab-delimited format with the missing surnames replaced by empty fields:

$ awk -v OFS='\t' 'NF == 3 { $1 = $1 } NF == 2 { $3 = $2; $2 = "" } { print }' <file
peter   barker  painter
carl    baker   cook
joshua          carpenter

The awk script will detect lines that contain two or three fields. It will simply reformat the lines that already has three fields into three tab-delimited fields while moving the second field into the third field for the lines that originally only contained two fields.

Then sort the data with tabs as delimiters:

$ awk -v OFS='\t' 'NF == 3 { $1 = $1 } NF == 2 { $3 = $2; $2 = "" } { print }' <file | sort -t $'\t' -k1,2 -k3
carl    baker   cook
joshua          carpenter
peter   barker  painter

The sorting done here is on the full name (fields one and two) and then by occupation. It is assumed that you are using a shell like bash that understands $'\t' as a tab character.


Instead of tabs, you may use any other character that does not interfere with the data (here :):

$ awk -v OFS=':' 'NF == 3 { $1 = $1 } NF == 2 { $3 = $2; $2 = "" } { print }' <file | sort -t ':' -k1,2 -k3
carl:baker:cook
joshua::carpenter
peter:barker:painter

Then replace the chosen delimiter character by passing the result through tr (here replacing with tabs, because it looks nice):

$ awk -v OFS=':' 'NF == 3 { $1 = $1 } NF == 2 { $3 = $2; $2 = "" } { print }' <file | sort -t ':' -k1,2 -k3 | tr ':' '\t'
carl    baker   cook
joshua          carpenter
peter   barker  painter

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.