简体   繁体   中英

How to get all lines from a file after the last empty line?

Having a file like foo.txt with content

1
2

3

4
5

How do i get the lines starting with 4 and 5 out of it (everything after last empty line), assuming the amount of lines can be different?

Updated

Let's try a slightly simpler approach with just sed .

$: sed -n '/^$/{g;D;}; N; $p;' foo.txt
4
5

-n says don't print unless I tell you to.
/^$/{g;D;}; says on each blank line, clear it all out with this:

  • g : Replace the contents of the pattern space with the contents of the hold space. Since we never put anything in , this erases the (possibly long accumulated) pattern space. Note that I could have used z since this is GNU, but I wanted to break it out for non-GNU sed 's below, and in this case this works for both.
  • D : remove the now empty line from the pattern space, and go read the next.

Now previously accumulated lines have been wiped if (and only if) we saw a blank line. The D loops back to the beginning, so N will never see a blank line.

  • N : Add a newline to the pattern space, then append the next line of input to the pattern space. This is done on every line except blanks, after which the pattern space will be empty.

This accumulates all nonblanks until either 1) a blank is hit, which will clear and restart the buffer as above, or 2) we reach EOF with a buffer intact.

Finally, $p says on the LAST line (which will already have been added to the pattern space unless the last line was blank, which will have removed the pattern space...), print the pattern space. The only time this will have nothing to print is if the last line of the file was a blank line.

So the whole logic boils down to: clean the buffer on empty lines, otherwise pile the non-empty lines up and print at the end.

If you don't have GNU sed , just put the commands on separate lines.

sed -n '
  /^$/{
   g
   D
  }
  N
  $p
' foo.txt

Alternate

The method above is efficient, but could potentially build up a very large pattern buffer on certain data sets. If that's not an issue, go with it.

Or, if you want it in simple steps, don't mind more processes doing less work each, and prefer less memory consumed:

last=$( sed -n /^$/= foo.txt|tail -1 ) # find the last blank
next=$(( ${last:-0} + 1 ))             # get the number of the line after
cmd="$next,\$p"                        # compose the range command to print
sed -n "$cmd" foo.txt                  # run it to print the range you wanted

This runs a lot of small, simple tasks outside of sed so that it can give sed the simplest, most direct and efficient description of the task possible. It will read the target file twice, but won't have to manage filling, flushing, and refilling the accumulation of data in the pattern buffer with records before a blank line. Still likely slower unless you are memory bound, I'd think.

Reverse the file, print everything up to the first blank line, reverse it again.

$ tac foo.txt | awk '/^$/{exit}1' | tac
4
5

Using GNU awk :

awk -v RS='\n\n' 'END{printf "%s",$0}' file

RS is the record separator set to empty line.

The END statement prints the last record.

try this:

 tail +$(($(grep -nE ^$ test.txt | tail -n1 | sed  -e 's/://g')+1)) test.txt
  • grep your input file for empty lines.
  • get last line with tail => 5:
  • remove unnecessary :
  • add 1 to 5 => 6
  • tail starting from 6

您可以尝试使用sed:

sed -n ':A;$bB;/^$/{x;s/.*//;x};H;n;bA;:B;H;x;s/^..//;p' infile

使用GNU sed:

sed ':a;/$/{N;s/.*\n\n//;ba;}' file

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM