sed: Indent with sed

For a nested XML-like format you can add indentation using sed by maintaining an indentation prefix in the hold space.

For example, for an icalendar file:

BEGIN:VCALENDAR
... Calendar properties
BEGIN:TZINFO
... Timezone properties
END:TZINFO
BEGIN:VEVENT
... Event properties
END:VEVENT
BEGIN:VEVENT
... Event properties
END:VEVENT
END:VCALENDAR

The following sed script will indent it:

#! /usr/bin/sed -Ef

/END:/ {              # Match close of section
  x                   # swap prefix out of hold
  s/^   //            # remove one level of indentation
  x                   # swap prefix back to hold
}

{                     # for all lines
  G                   # append prefix as another line
  s/(.*)\n(.*)/\2\1/  # move prefix before input line
}                     # (implicit print at end)

/BEGIN:/ {            # Match start of section
  x                   # swap prefix out of hold
  s/^/   /            # add one level of indentation
  x                   # swap prefix back to hold
}

Or more tersely:

#! /usr/bin/sed -Ef
/END:/   { x; s/^   //; x; }
         { G; s/(.*)\n(.*)/\2\1/; }
/BEGIN:/ { x; s/^/   /; x; }

Result of running that script on the sample input:

BEGIN:VCALENDAR
   ... Calendar properties
   BEGIN:TZINFO
      ... Timezone properties
   END:TZINFO
   BEGIN:VEVENT
      ... Event properties
   END:VEVENT
   BEGIN:VEVENT
      ... Event properties
   END:VEVENT
END:VCALENDAR
Published on: 15 Jun 2022