4

If I have a file with contents similar to:

FirstSection
    Unique first line in first section
    Unique second line in first section

SecondSection
    Unique first line in second section
    Unique second line in second section

...

NthSection
    Unique first line in Nth section
    Unique second line in Nth section

Is it possible to use unix commands (e.g. sort, awk) to sort the file alphabetically by the first non-indented line in each three line group, whilst keeping the indented lines under their existing group?

2
  • 2
    each group is always three lines? – Jeff Schaller Jun 10 '19 at 16:39
  • 1
    Not necessarily. I should have made that clearer with the example. – tacgnol Jun 11 '19 at 17:32
6

Using Perl you could run something along the lines of:

  • slurp the file (perl -0n)
  • split the input by not indented lines split(/^(?=\S)/m)
  • sort and print

perl -0ne 'print sort split(/^(?=\S)/m) ' ex 
4
  • I really like how short and simple your perl code is. I had to use three commands. But the output format is a bit ugly: two trailing newlines, no empty line between the sections NthSection and SecondSection. If you do these, I'll up-vote you. – seshoumara Jun 12 '19 at 7:50
  • 2
    This worked fine for me. very succinct. Perl tends to get forgotten these days, but it did the job without me needing to install additional software on my workstation. – tacgnol Jun 12 '19 at 8:33
  • @tacgnol, thank you. – JJoao Jun 12 '19 at 13:09
  • 1
    @seshoumara, sorry, i missed your comment. Following an alternative for more controlled output format (it is a bit ugly...) perl -0nE 'say for sort /^(\S.*?\n)\s*(?=^\S|\z)/smg ' ex – JJoao Nov 3 '20 at 16:59
3

First sed puts each section on a single line, using the text <EOL> as delimiter between section lines. Then I'm sorting the sections and using the second sed to revert each <EOL> back to a newline.

sed -r ':r;$!{N;br};s:\n([[:blank:]])(\1*):<EOL>\1\2:g' file|sort|sed -r '/^$/d;:l;G;s:(.*)<EOL>(.*)(\n):\1\3\2:;tl;$s:\n$::'

I didn't chose a character as a delimiter, since the input file might have it, so I used <EOL> instead.

Output: I added a newline after each section, except the last, to recreate the style of the input file.

FirstSection
    Unique first line in first section
    Unique second line in first section

NthSection
    Unique first line in Nth section
    Unique second line in Nth section

SecondSection
    Unique first line in second section
    Unique second line in second section
4
  • I cannot get that to work with FreeBSD or Macos which are the main OSs I use due to the -z option not being recognised. I tried GNU sed 4.2.1 on a linux system I have to hand, but it doesn't recognise the -z option either. – tacgnol Jun 11 '19 at 17:39
  • @tacgnol You have a very old version of GNU sed on that Linux system, from about a decade ago. Current version is 4.7. I modified my answer to not use the -z feature, I hope it works for you. If not, let me know. – seshoumara Jun 11 '19 at 21:05
  • I could not get that to work on macOS, even with a newly installed version of gnu sed 4.7. It runs without error, but the output for each section is all on one line, with the lines in each section separated by tabs. I also found a linux host with gnu sed 4.6 and it works as expected sorting the file, by section, alphabetically. – tacgnol Jun 12 '19 at 8:25
  • @tacgnol I think the problem might be that \n isn't recognized in the replacement part of the s command. The workaround is ugly, but I hope it works now. I also worked around \s, that is not posix. – seshoumara Jun 12 '19 at 20:09
0

with awk we could do hold every group into an awk associated array based on line-break between each group; then asort() and print its sorted by for-loop used.

awk '/^$/{ ++group; next} { saving[group]=(saving[group]==""? $0 : saving[group] RS $0) }
END{ asort(saving); 
     for(group in saving) print saving[group]
}'  infile

note: you can use PROCINFO["sorted_in"] element to set which type of sort you need; for example PROCINFO["sorted_in"]="@val_str_desc" will sort the value of our array as string and in desc order.

testing on an input file like:

BFirstSection
    Unique first line in first section
    Unique second line in first section

DSecondSection
    Unique first line in second section
    Unique second line in second section

Aanothersection...
    ...
    ...

CfourthSection
    Unique first line in Nth section
    Unique second line in Nth section

you will get output as:

Aanothersection...
    ...
    ...
BFirstSection
    Unique first line in first section
    Unique second line in first section
CfourthSection
    Unique first line in Nth section
    Unique second line in Nth section
DSecondSection
    Unique first line in second section
    Unique second line in second section
1
  • what should I modify I want to sort the groups based of the value of the 3rd clumn of the 1st line of each group @αғsнιη – Mohsen El-Tahawy Feb 5 at 20:19

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.