Home » Linux » Tail inverse / printing everything except the last n lines?

Tail inverse / printing everything except the last n lines?

Posted by: admin November 29, 2017 Leave a comment

Questions:

Is there a (POSIX command line) way to print all of a file EXCEPT the last n lines? Use case being, I will have multiple files of unknown size, all of which contain a boilerplate footer of a known size, which I want to remove. I was wondering if there is already a utility that does this before writing it myself.

Answers:

Most versions of head(1) – GNU derived, in particular, but not BSD derived – have a feature to do this. It will show the top of the file except the end if you use a negative number for the number of lines to print.

Like so:

head -n -10 textfile

Questions:
Answers:

Probably less efficient than the “wc” + “do the math” + “tail” method, but easier to look at:

tail -r file.txt | tail +NUM | tail -r

Where NUM is one more than the number of ending lines you want to remove, e.g. +11 will print all but the last 10 lines. This works on BSD which does not support the head -n -NUM syntax.

Questions:
Answers:

There’s no standard commands to do that, but you can use awk or sed to fill a buffer of N lines, and print from the head once it’s full. E.g. with awk:

awk -v n=5 '{if(NR>n) print a[NR%n]; a[NR%n]=$0}' file

Questions:
Answers:

The head utility is your friend.

From the man page of head:

-n, --lines=[-]K
     print the first K lines instead of the first 10;
       with the leading `-', print all but the last K lines of each file
Questions:
Answers:

If the footer starts with a consistent line that doesn’t appear elsewhere, you can use sed:

sed '/FIRST_LINE_OF_FOOTER/q' filename

That prints the first line of the footer; if you want to avoid that:

sed -n '/FIRST_LINE_OF_FOOTER/q;p' filename

This could be more robust than counting lines if the size of the footer changes in the future. (Or it could be less robust if the first line changes.)

Another option, if your system’s head command doesn’t support head -n -10, is to precompute the number of lines you want to show. The following depends on bash-specific syntax:

lines=$(wc -l < filename) ; (( lines -= 10 )) ; head -$lines filename

Note that the head -NUMBER syntax is supported by some versions of head for backward compatibility; POSIX only permits the head -n NUMBER form. POSIX also only permits the argument to -n to be a positive decimal integer; head -n 0 isn’t necessarily a no-op.

A POSIX-compliant solution is:

lines=$(wc -l < filename) ; lines=$(($lines - 10)) ; head -n $lines filename

If you need to deal with ancient pre-POSIX shells, you might consider this:

lines=`wc -l < filename` ; lines=`expr $lines - 10` ; head -n $lines filename

Any of these might do odd things if a file is 10 or fewer lines long.

Questions:
Answers:

It is simple. You have to add + to the number of lines that you wanted to avoid.

This example gives to you all the lines except the first 9

tail -n +10 inputfile

(yes, not the first 10…because it counts different…if you want 10, just type
tail -n 11 inputfile)