9

I am trying to sort a list of names followed by another string such as:

John Doe
AVAIL

Sara Doe
CALL

Jim Doe
AVAIL

I am trying to sort these by name but can't seem to figure it out with sort. Can someone provide some guidance?

My final output would look like this:

Jim Doe
AVAIL

John Doe
AVAIL

Sara Doe
CALL

Much appreciated!

2
  • Interestingly, from your example, its not clear whether you sort with respect to the first or the second line ;) Commented Jul 3, 2012 at 17:16
  • Sorry I would actually like to sort by alphabetical order for the first line. Commented Jul 3, 2012 at 17:17

3 Answers 3

10

Probably far from optimal, but

sed -r ':r;/(^|\n)$/!{$!{N;br}};s/\n/\v/g' names | sort | sed 's/\v/\n/g'

seems to do the job (names is the file with records). This allows records of arbitrary length, not just 2 lines.

Sign up to request clarification or add additional context in comments.

5 Comments

@lev for those not quite "fluent" in sed could you give a short narration of the first part of the expression? Is your basic approach eliminating newlines (putting \v? in its place), sorting a long line, and then replacing the \v for \n?
@Levon You're exactly right :) It reads everything up to an empty line (one record), then changes newlines in it to \v. Now all records are on single lines. They are sorted, then \v is converted back to \n.
+1 @LevLevitsky Great .. thanks. I am using SO to learn a bunch of new things :-) .. plus others might come across this at some time too. Thanks for the reply/explanation.
Just a quick question for slightly changing this logic. How would you change it when you need to separate records not by empty lines, but by sequence of characters "---" ?
@martinnovoty Can the same sequence be encountered inside records? If not, it's even easier: change all newlines to \v, then change --- to newlines, then sort, then change \v to \n.
0

Not sure if it's going to work for you but with some limitations here is a line that kind of doing what you need.

awk '{if ((NR%2-1)==0) {line=sprintf("%-30s",$0)} else {print line ":" $0}}' | \
  sort --key=1,30 | tr ':' '\n'

Assumptions: There are no blank lines in between records, name is always less than 30 characters and there is no : used in text.

I am sure you can figure how to change it if assumptions are different.

In a nutshell it, merges two lines using ':' as separator, pads first line to 30 characters and sorts using first 30 characters. Then it breaks lines back.

Comments

0

not directly, but you can use some intermediate form like this. i am assuming that your value (CALL, AVAIL, etc.) is limited. otherwise you need to use patterns that are more complicated, but it can be done. actually anything can be done in bash :-)

cat sorting | sed -n '1h; 1!H; ${ g; s/\nCALL\n/::CALL::/g; s/\nAVAIL\n/::AVAIL::/g ; s/\nAVAIL/::AVAIL::/g p }' | sort | sed "s/::/\n/g"
Jim Doe
AVAIL

John Doe
AVAIL

Sara Doe
CALL

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.