1

I'm trying to write a short script that finds empty lines and then prints the nth line after the empty lines.

For

foo1
foo2
foo3

bar1
bar2
bar3

spam1
spam2
spam3

eggs1
eggs2
eggs3

printing every 2nd line after a blank line would result in:

foo2
bar2
spam2
eggs2

I tried using sed sed -n -e "/^$/ {N; N; x; N; p; x; d}" but I cannot get the hold space to be cleared and the result is not what I want.

2
  • 1
    You seem to be counting line zero as a blank line when you say "every 2nd line after a blank line." – Wildcard Mar 25 '16 at 22:33
  • @Alexandru Give a try to the sed example in my answer. foo2 cannot be fetched because the example data file does not start with an empty line. There is also a complete solution with awk. – Jay jargot Mar 28 '16 at 10:15
8
awk '++n == 2; !NF {n = 0}' < your-file

Or:

sed -n '
  n;p
  :1
  /./{
    n;b1
  }' < your-file
2
  • I love the awk version, simple and elegant. As for the sed one, well, it's cleverly short, but I can't resist being reminded of Djikstra's Go To statement considered harmful ^^ – Olivier Dulac Apr 3 '16 at 19:54
  • 1
    For readers like me who needs help on the sed one, here is a brief explanation of both: The awk version is both things are done on each lines: Increase n (start at 0) each line, and IF we now have n == 2, print $0 (default action). !NF : is true when there are no fields (ie, line is empty), and in that case: reset n to 0. The 2nd one (sed) is : go to next line; print it. Then for each following non-empty lines (ie: at least 1 char): go to next line, and branch on label 1 (thus ignoring those n>2 lines). When condition doesn't match, loop (because of the -n) to the beginning – Olivier Dulac Apr 3 '16 at 20:03
1

You're counting line zero as a blank line, which makes it a bit harder. If we ignore that and take your literal statement, "print every second line after a blank line", you can do it like so with ex:

ex -sc 'g/^$/+2p' -cq filename
  • -s: silent mode (ex is actually for interactive editing).
  • -c: state a command to be run
  • g/^$/: run the following command globally on all empty lines
  • +2p: print the line two lines down from the current line
  • q: the command to quit

To count line 0 as a blank line (but only if line 1 is not a blank line) you have to get fancier; you could do it in ex by inserting a blank line before line 1, then filtering lines 1-2 through uniq—but at that point you're probably better off using awk, for your purposes.

1

Easily done with perl:

$ perl -n -e 'BEGIN {$count=0}; 
              if (/^\s*$/) {$count=0} else {$count++};
              if ($count eq 2) {print}' alexandru.txt 
foo2
bar2
spam2
eggs2
0

You can use awk to remember the last line that was empty:

awk -v gap=2 'BEGIN { lastline=0 } /^$/ { lastline=NR } NR==lastline+gap { print }' test.txt

This means:

  • In the beginning, set the variable that indicates what the last line was (lastline) to zero. This matches your implied requirement that the second line would be printed as if it came after an empty line.
  • When in an empty line, set lastline to the current line.
  • When the current line number is gap lines after the last empty lines, print it.

You can set gap in the beginning to any number. Note that if there are less than gap lines between two empty lines, the first empty line will have no effect.

0

There is a harcoded value 2 to print each 2nd lines after the empty one.

Give it a try:

awk 'BEGIN { empty=1; n=0; } { if ($0 ~ /^$/) { empty=1; n=0; } else if (empty) { n++; if (n==2) { empty=0; print; } } }' file.txt

file.txt is the name of the file to parse in the current directory.

It is assumed that there are always n lines or more after each empty lines, when searching for nth one, right?

The test output is below:

awk 'BEGIN { empty=1; n=0; } { if ($0 ~ /^$/) { empty=1; n=0; } else if (empty) { n++; if (n==2) { empty=0; print; } } }' file.txt
foo2
bar2
spam2
eggs2

----

There is a famous page: Sed - An Introduction and Tutorial by Bruce Barnett

Give a try to this version below which is very close to yours:

sed -n '{
2 {
p
}
/^$/ {n
n
p}}' file.txt

foo2
bar2
spam2
eggs2
0

To print the lnb'th line after first blank (empty) line...

Line number to print :

lnb=2

With sed :

sed -ne '/^\s*$/{:a;n;0~'"$lnb"'!ba;p;q}' my_file

With perl :

perl -ne '/^\s+$/ && $k++;$k!=0 && $k++ && $k=='"$lnb"'+2 && (print,last)' my_file
1
  • thanks for formatting :) – lerems04 May 23 '19 at 12:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.