Question

I have a file that is in the following format:

First Name : aa
#some noninteresting info
...
#some noninteresting info
Last Name : tt
First Name : cc
#some noninteresting info
...
#some noninteresting info
Last Name : ss

I need to produce another file which only has first and last names and is sorted based on last name:

First Name : cc
Last Name : ss
First Name : aa
Last Name : tt

I tried the following:

grep "Last Name :" | sort 

But this is only half of what I want. How can I add First Name to this which corresponds to the last name and keep them sorted based on the last name?

Was it helpful?

Solution

If you have GNU sed then you can pipe the output of grep to it.

grep -E '(First|Last) Name' file | sed 'N;s/\n/ /' | sort -k8 | sed 's/Last/\nLast/'
First Name : cc
Last Name : ss
First Name : aa
Last Name : tt
  • grep -E '(First|Last) Name' file will grep the lines with First and Last Names
  • sed 'N;s/\n/ /' will add the append the Last Name to First Name
  • sort -k8 will sort the 8th field which is Last Name value
  • sed 's/Last/\nLast/' will place them on separate lines

If you don't have GNU sed then your other option would be to use xargs:

grep -E '(First|Last) Name' file | xargs -n8 | sort -k8 | xargs -n4
First Name : cc
Last Name : ss
First Name : aa
Last Name : tt

Note: This assumes that your data has First Name and Last Names for every entries. xargs solution assumes that your First Name has no Middle Name

OTHER TIPS

You can easily use regular expressions to accomplish the filtering:

grep -E "(Last|First) Name :"

But to have them "in order" of last name while displaying the first name, you'll need to do more processing before you sort. Perhaps you can look at sed and awk to help with that part.

A way you can do this is by changing the regular expressions to have a single match encompass both first and last name's lines, append the last name to the beginning of the match, sort it, and remove the last name.... complex, but a doable method.

Using a perl one-liner

perl -e 'print sort {@l = map /([^:]*)\Z/, $a, $b; $l[0] cmp $l[1]} split /(?=^First)/m, join q{}, grep /Name :/, <>' file.txt

Breaking it down. Read bottom to top.

perl -e '
     print                                                   # Print results
     sort {@l = map /([^:]*)\Z/, $a, $b; $l[0] cmp $l[1]}    # Sort based off last phrase after a :
     split /(?=^First)/m,                                    # Split on lines beginning with First
     join q{},                                               # Join all lines together
     grep /Name :/,                                          # Filter all those not containing Name :
     <>                                                      # Slurp all the lines
   ' file.txt
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top