How do I insert a newline for every two lines, except when two consecutive newlines are encountered?
I am trying to insert a new line for every two lines of text, except that I want to rerun this pattern whenever a new paragraph is encountered (two consecutive new lines). (My desired output should not have three consecutive new lines.)
For example, here's my input text:
This is my first
line to appear in
the text.
I need the second
line to appear in
the way that follows
the pattern specified.
I am not sure if
the third line will
appear as I want it
to appear because sometimes
the new line happens where
there are two consecutive
new lines.
And here is my desired output:
This is my first
line to appear in
the text.
I need the second
line to appear in
the way that follows
the pattern specified.
I am not sure if
the third line will
appear as I want it
to appear because sometimes
the new line happens where
there are two consecutive
new lines.
I've tried using awk:
awk -v n=2 '1; NR % n == 0 {print ""}'
but this command does not restart the template after a new paragraph. Instead, I would get the following output from my example above:
This is my first
line to appear in
the text.
I need the second
line to appear in
the way that follows
the pattern specified.
I am not sure if
the third line will
appear as I want it
to appear because sometimes
the new line happens where
there are two consecutive
new lines.
As this unwanted output shows, without restarting the template, I would get instances of three consecutive newlines.
source to share
Perl's paragraph mode can help:
perl -00 -ple 's/.*\n.*\n/$&\n/g'
Output
This is my first
line to appear in
the text.
I need the second
line to appear in
the way that follows
the pattern specified.
I am not sure if
the third line will
appear as I want it
to appear because sometimes
the new line happens where
there are two consecutive
new lines.
Based on @ Borodin's comment:
perl -00 -ple 's/(?:.*\n){2}\K/\n/g'
source to share
Pearl for the rescue!
perl -00 -ple '$i = 0; s/\n/($i++ % 2) ? "\n\n" : "\n"/eg'
-
-00
turns on paragraph mode, that is, Perl reads input in blocks separated by at least two newlines. -
-l
removes two newlines from the end of each block after reading it, but returns them before printing, avoiding three consecutive newlines. -
/e
evaluates the right side of the substitution as code. -
$i++ % 2
is the increment plus modulus. It returns 1 for rows 1, 3, 5, etc. In every block. -
condition ? then : else
is a ternary operator. New lines on lines 1, 3, 5 ... will be replaced with two new lines, the rest will remain. -
$i
- reset so that each block starts at 0 again.
source to share
This will also restart the template for each paragraph:
use strict;
use warnings;
my $str = do { local $/; <DATA> };
my $i = 0;
$str =~ s/(\n+)/
if (length $1 > 1) {
$i = 0;
"\n\n";
}
else {
$i++ % 2 ? "\n\n" : "\n"
}
/ge;
print $str;
__DATA__
This is my first
line to appear in
the text.
I need the second
line to appear in
the way that follows
the pattern specified.
I am not sure if
the third line will
appear as I want it
to appear because sometimes
the new line happens where
there are two consecutive
new lines.
Output
This is my first
line to appear in
the text.
I need the second
line to appear in
the way that follows
the pattern specified.
I am not sure if
the third line will
appear as I want it
to appear because sometimes
the new line happens where
there are two consecutive
new lines.
source to share
This might work for you (GNU sed):
sed '/\S/!d;n;//!b;$!G' file
Remove all blank lines in front of the non-blank line, print it, if the next line is blank, you can add a new line (if it is not the last line) and repeat.
If you prefer an empty string to indicate the last true verse:
sed '/\S/!d;n;//G' file
As an afterthought to group consecutive lines sequentially:
sed '/\S/!d;:a;N;/\n\s*$/b;s/[^\n]*/&/5;Ta;G' file
This will divide the texts into groups of no more than five lines.
source to share
If you wait if the next line is empty to decide to insert a new line, it becomes relatively easy. Here expressed in awk:
parse.awk
# Remember line count in the paragraph with n NF { n++ } !NF { n=0 } # Only emit new-line if n is non-zero and the previous line # number is divisible by m n>=m && (n-1)%m==0 { printf "\n" } # Print $0 1
Run it like this:
awk -v m=2 -f parse.awk file
Or, for example, like this:
awk -f parse.awk m=2 file m=3 file
Below is the output of the second call, followed by the header added to the script (the header is specific to GNU awk):
BEGINFILE {
n = 0;
if(FNR != NR)
printf "\n\n"; print "===>>> " FILENAME ", m=" m " <<<==="
}
Output:
===>>> file, m=2 <<<===
This is my first
line to appear in
the text.
I need the second
line to appear in
the way that follows
the pattern specified.
I am not sure if
the third line will
appear as I want it
to appear because sometimes
the new line happens where
there are two consecutive
new lines.
===>>> file, m=3 <<<===
This is my first
line to appear in
the text.
I need the second
line to appear in
the way that follows
the pattern specified.
I am not sure if
the third line will
appear as I want it
to appear because sometimes
the new line happens where
there are two consecutive
new lines.
Golf version:
{n=NF?n+1:0}(n-1)%m==0&&n>=m{printf "\n"}1
source to share