Indent lines of text following given rule

I was wondering how indenting recursively more and more lines of poetry following a custom rule. For instance

Let say we have:

OF Mans First Disobedience, and the Fruit
Of that Forbidden Tree, whose mortal tast
Brought Death into the World, and all our woe,
With loss of Eden, till one greater Man
Restore us, and regain the blissful Seat,
Sing Heav'nly Muse, that on the secret top
Of Oreb, or of Sinai, didst inspire
That Shepherd, who first taught the chosen Seed,
In the Beginning how the Heav'ns and Earth
Rose out of Chaos: Or if Sion Hill
Delight thee more, and Siloa's Brook that flow'd
Fast by the Oracle of God; I thence
Invoke thy aid to my adventrous Song,
That with no middle flight intends to soar
Above th' Aonian Mount, while it pursues
Things unattempted yet in Prose or Rhime.
And chiefly Thou O Spirit, that dost prefer
Before all Temples th' upright heart and pure,
Instruct me, for Thou know'st; Thou from the first
Wast present, and with mighty wings outspread.

And we want to indent it, recursively, adding 3 spaces to any three lines after the first, in this way

OF Mans First Disobedience, and the Fruit
   Of that Forbidden Tree, whose mortal tast
   Brought Death into the World, and all our woe,
   With loss of Eden, till one greater Man
Restore us, and regain the blissful Seat,
   Sing Heav'nly Muse, that on the secret top
   Of Oreb, or of Sinai, didst inspire
   That Shepherd, who first taught the chosen Seed,
In the Beginning how the Heav'ns and Earth
   Rose out of Chaos: Or if Sion Hill 
   Delight thee more, and Siloa's Brook that flow'd
   Fast by the Oracle of God; I thence
Invoke thy aid to my adventrous Song,
   That with no middle flight intends to soar
   Above th' Aonian Mount, while it pursues
   Things unattempted yet in Prose or Rhime.
And chiefly Thou O Spirit, that dost prefer
   Before all Temples th' upright heart and pure,
   Instruct me, for Thou know'st; Thou from the first
   Wast present, and with mighty wings outspread

What can be the simplest way to achieve this goal?

Asked By: Dingo

||

If you just want to indent the first line and then every 4th line after that, you can use awk:


$ awk 'NR % 4 != 1{$0="    "$0};1' file 
OF Mans First Disobedience, and the Fruit
    Of that Forbidden Tree, whose mortal tast
    Brought Death into the World, and all our woe,
    With loss of Eden, till one greater Man
Restore us, and regain the blissful Seat,
    Sing Heav'nly Muse, that on the secret top
    Of Oreb, or of Sinai, didst inspire
    That Shepherd, who first taught the chosen Seed,
In the Beginning how the Heav'ns and Earth
    Rose out of Chaos: Or if Sion Hill
    Delight thee more, and Siloa's Brook that flow'd
    Fast by the Oracle of God; I thence
Invoke thy aid to my adventrous Song,
    That with no middle flight intends to soar
    Above th' Aonian Mount, while it pursues
    Things unattempted yet in Prose or Rhime.
And chiefly Thou O Spirit, that dost prefer
    Before all Temples th' upright heart and pure,
    Instruct me, for Thou know'st; Thou from the first
    Wast present, and with mighty wings outspread.

Or perl:

$ perl -pe 's/^/    / if $. % 4 != 1' file
OF Mans First Disobedience, and the Fruit
    Of that Forbidden Tree, whose mortal tast
    Brought Death into the World, and all our woe,
    With loss of Eden, till one greater Man
Restore us, and regain the blissful Seat,
    Sing Heav'nly Muse, that on the secret top
    Of Oreb, or of Sinai, didst inspire
    That Shepherd, who first taught the chosen Seed,
In the Beginning how the Heav'ns and Earth
    Rose out of Chaos: Or if Sion Hill
    Delight thee more, and Siloa's Brook that flow'd
    Fast by the Oracle of God; I thence
Invoke thy aid to my adventrous Song,
    That with no middle flight intends to soar
    Above th' Aonian Mount, while it pursues
    Things unattempted yet in Prose or Rhime.
And chiefly Thou O Spirit, that dost prefer
    Before all Temples th' upright heart and pure,
    Instruct me, for Thou know'st; Thou from the first
    Wast present, and with mighty wings outspread.

In both cases, we are adding 4 spaces to the beginning of the line if the current line number module 4 is not equal to 1, which means we will do it for all lines except the 1st, 4th and so on.

In awk, NR is the line number, and $0 is the contents of the line, so NR % 4 != 1{$0=" "$0}; means "add 4 spaces to the beginning of the line when the current line number modulo 4 is not equal to 1". The final 1; is just shorthand for "print".

In Perl, $. is the current line number, and s/old/new/ is the subsitution operator which will replace the first occurrence of old with new. So s/^/ / if $. % 4 != 1 means "replace the beginning of the line (^) with four spaces if the current line number modulo 4 is not equal to 1". The -p means "print each line of the input file after applying the script provided by -e".

Here is the exact same perl command in a more verbose and easier to understand version:

perl -e '
open(my $fileHandle, "<", $ARGV[0]);
my $lineCount=0;

while(my $line = <$fileHandle>){
   $lineCount += 1;
   if ( $lineCount % 4 != 1 ){
       ## or $line = "    " . $line
       $line =~ s/^/    /
   }
   print "$line";
}' file

Or, almost identical:

perl -e '
open(my $fileHandle, "<", $ARGV[0]);
my $lineCount=0;

while(my $line = <$fileHandle>){
   $lineCount += 1;
   unless ( $lineCount % 4 == 1 ){
       $line = "    " . $line
   }
   print "$line";
}' file
Answered By: terdon

Using Raku (formerly known as Perl_6)

Autoprinting (first two below):

raku -pe 's/^/    / if $++ % 4;'  

OR

raku -pe 'state $i; s/^/    / if $i++ % 4;'  

OR (non-autoprinting, next two below)

raku -ne '$++ % 4 ?? put "    $_" !! put "$_";' 

OR (non-autoprinting, no internal quotes)

raku -ne 'state $i; $i++ % 4 ?? qq[    $_].put !! $_.put;' 

Raku code above, first two examples are a direct translation of @terdon’s Perl(5) one-liner code (-pe flags). Raku uses $_ as topic variable–same as Perl. Note Raku dispenses with a number of special variables in favor of state variables which get initialized only once. The commonly used state variables include $ and incremented/decremented forms such as $++ (anonymous scalar, here used to count line-numbers).

The last two examples are non-autoprinting (-ne flags), and use Raku’s "?? True !! False" ternary operator. These forms are conceptually similar to @Ed_Morton’s awk code (comment). An attempt was made to keep parallel text in each half of Raku’s ternary, but in truth all you need to do when outputting the $_ topic variable is to write .put (Raku defaults to the $_ topic variable if not explicitly stated). Also, put in Raku adds the n newline for you.

Finally, a lot of quoting problems in Raku are solved using the "Q-language", which is referenced below (example in the fourth one-liner above using qq[…] ).

Sample Output (all 4 one-liners, above):

OF Mans First Disobedience, and the Fruit
    Of that Forbidden Tree, whose mortal tast
    Brought Death into the World, and all our woe,
    With loss of Eden, till one greater Man
Restore us, and regain the blissful Seat,
    Sing Heav'nly Muse, that on the secret top
    Of Oreb, or of Sinai, didst inspire
    That Shepherd, who first taught the chosen Seed,
In the Beginning how the Heav'ns and Earth
    Rose out of Chaos: Or if Sion Hill
    Delight thee more, and Siloa's Brook that flow'd
    Fast by the Oracle of God; I thence
Invoke thy aid to my adventrous Song,
    That with no middle flight intends to soar
    Above th' Aonian Mount, while it pursues
    Things unattempted yet in Prose or Rhime.
And chiefly Thou O Spirit, that dost prefer
    Before all Temples th' upright heart and pure,
    Instruct me, for Thou know'st; Thou from the first
    Wast present, and with mighty wings outspread.

https://docs.raku.org/syntax/state
https://docs.raku.org/language/quoting
https://docs.raku.org/language/operators#index-entry-operator_ternary

Answered By: jubilatious1