Opposite of tail: all lines except the last n lines

If you have GNU head, you can use

head -n -5 file.txt

to print all but the last 5 lines of file.txt.

If head -n takes no negative arguments, try

head -n $(( $(wc -l file.txt | awk '{print $1}') - 5 )) file.txt

head file.txt               # first 10 lines
tail file.txt               # last 10 lines
head -n 20 file.txt         # first 20 lines
tail -n 20 file.txt         # last 20 lines
head -20 file.txt           # first 20 lines
tail -20 file.txt           # last 20 lines
head -n -5 file.txt         # all lines except the 5 last
tail -n +5 file.txt         # all lines except the 4 first, starts at line 5

Here's a simple way to delete the last line, which works on BSD, etc.

sed '$d' input.txt

The expression reads "on the last line, delete it". The other lines will be printed, since that is sed's default behavior.

You could chain them together to remove multiple lines

sed '$d' input.txt | sed '$d' | sed '$d'

Which is a little heavy-handed, admittedly, but does only one scan through the file.

You can also take a look at this, for more answers: https://stackoverflow.com/questions/13380607/how-to-use-sed-to-remove-last-n-lines-of-a-file

Here's a one-liner adapted from one of my favorites there:

count=10
sed -n -e ':a' -e "1,$count"'!{P;N;D;};N;ba'

I had fun deciphering that one, and I hope you do, too (: It does buffer count lines as it scans, but otherwise is pretty efficient.

Note: the ! is quoted using single-quotes to avoid it being interpreted by Bash (if that's your shell). Plain double-quotes around the whole thing works for sh, possibly others.