3

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?

0

2 Answers 2

7

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
11
  • 1
    GNU sed: sed '1~4!s/^/ /' file. Non-GNU sed: sed 'N;N;N;s/\n/& /g' file Commented Jun 12, 2022 at 11:25
  • Thanks, @Kusalananda, I knew there was a simple sed way but couldn't remember, go ahead and post an answer! Commented Jun 12, 2022 at 11:45
  • 2
    awk '{print (NR % 4 == 1 ? "" : " ") $0}' file would me more efficient as it doesn't modify $0 and so force field splitting and only has 1 condition to test. Testing a positive (==) is also a bit clearer than a negative (!=). Commented Jun 13, 2022 at 1:14
  • It's interesting (to me anyway) that you came up with 2 different solutions for 2 different tools that each have both capabilities. In awk you did a string assignment to put 4 blanks at the start of the record $0=" "$0 while in perl you did a regexp replacement of the start of the line with 4 blanks s/^/ /. You could have done sub(/^/," ") in awk and I assume you could have done $_=" "$_ (or whatever the syntax is) in perl. I wonder what made you go in 2 different directions for the same problem... Commented Jun 13, 2022 at 11:39
  • 1
    Ha! @EdMorton habit, nothing else. I could indeed have done $_=" $_", it just didn't occur to me. I've been using both perl and awk daily for many years, and some idioms seem to just be ingrained. Commented Jun 13, 2022 at 12:13
1

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

1
  • At the risk of confusing the OP, I could even add a fifth example: raku -ne 'put $++ % 4 ?? q[ ] ~ $_ !! $_;' (...but that would require me to explain that string-concatenation in Raku is accomplished with ~ tilde). Commented Jun 15, 2022 at 3:10

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.