5

Is it possible to sort a markdown file by level 1 heading? Looking for sed or similar command line solution

#B
a content of B

#A
b content of A

to...

#A
b content of A

#B
a content of B
HelenFr
  • 53
  • 3
  • Sed or awk should be feasible. But a more structured way would be to parse it and restructure it. E.g., [this](https://pythonhosted.org/Markdown/) seems to be a python library that understands and parses markdown documents. – KFL Aug 17 '14 at 18:11

3 Answers3

2

A perl one-liner, split for readability

perl -0777 -ne '
    (undef,@paragraphs) = split /^#(?=[^#])/m; 
    print map {"#$_"} sort @paragraphs;
' file.md

You'll want to end the file with a blank line, so there's a blank line before #B. Or you could change
map {"#$_"} to map {"#$_\n"} to forcibly insert one.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

You can use GNU Awk with PROCINFO["sorted_in"] = "@ind_str_asc":

gawk 'BEGIN { PROCINFO["sorted_in"] = "@ind_str_asc"; RS = ""; ORS = "\n\n" }
      { a[$1] = $0 } END { for (i in a) print a[i] }' file

Output:

#A
b content of A

#B
a content of B

Reference:

PROCINFO["sorted_in"]

   If this element exists in PROCINFO,
   then its value controls the order in
   which array elements are traversed in
   for loops.  Supported values are
   "@ind_str_asc", "@ind_num_asc",
   "@val_type_asc", "@val_str_asc",
   "@val_num_asc", "@ind_str_desc",
   "@ind_num_desc", "@val_type_desc",
   "@val_str_desc", "@val_num_desc", and
   "@unsorted".  The value can also be the
   name of any comparison function defined
   as follows:
konsolebox
  • 72,135
  • 12
  • 99
  • 105
0

you can also use this script to have the sorting on 3 levels instead of just one. It also won't stripe out the content before the first occurence of the first heading.

#!/usr/bin/env perl

local $/;
my $text = <>;
my ($start, @chapters) = split/^#(?=[^#])/m, $text;
print $start;
for (sort @chapters) {
    my ($level1, @subchapters) = split/^##(?=[^#])/m;
    print "#$level1";
        for (sort @subchapters) {
        my ($level2, @subsubchapters) = split/^###(?=[^#])/m;
        print "##$level2";
        print map {"###$_"} sort @subsubchapters; 
        }
}