22

Variants of this question have certainly been asked several times in different places, but I am trying to remove the last M lines from a file without luck.

The second most voted answer in this question recommends doing the following to get rid of the last line in a file:

head -n -1 foo.txt > temp.txt

However, when I try that in OSX & Zsh, I get:

head: illegal line count -- -1

Why is that? How can I remove the M last lines and the first N lines of a given file?

Amelio Vazquez-Reina
  • 40,169
  • 77
  • 197
  • 294

3 Answers3

29

You can remove the first 12 lines with:

tail -n +13

(That means print from the 13th line.)

Some implementations of head like GNU head support:

head -n -12

but that's not standard.

tail -r file | tail -n +13 | tail -r

would work on those systems that have tail -r (see also GNU tac) but is sub-optimal.

Where n is 1:

sed '$d' file

You can also do:

sed '$d' file | sed '$d'

to remove 2 lines, but that's not optimal.

You can do:

sed -ne :1  -e 'N;1,12b1' -e 'P;D'

But beware that won't work with large values of n with some sed implementations.

With awk:

awk -v n=12 'NR>n{print line[NR%n]};{line[NR%n]=$0}'

To remove m lines from the beginning and n from the end:

awk -v m=6 -v n=12 'NR<=m{next};NR>n+m{print line[NR%n]};{line[NR%n]=$0}'
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • `sed 'x;1d;$d'` might be used to get the last two lines as well. And w/ a couple of `N`'s after `1d` might be used to get a little more than that, though at that point it offers no advantage over the `N;P;D` loop you already recommend. – mikeserv Nov 21 '14 at 00:46
  • Thank you -- The last command is extremely helpful. A summer small caveat: it doesn't work when `m` or `n` are `0`. Otherwise it would be perfect. – Amelio Vazquez-Reina Nov 21 '14 at 21:13
  • @AmelioVazquez-Reina, it should work for `m` == 0. For `n` == 0, just use `tail`, using `awk` for that would be overkill (though that should just be `awk -v m=12 'NR > m'`) – Stéphane Chazelas Jan 06 '23 at 14:46
  • it's kinda bizarre that tail supports `+13` but head does not support `-13`. Lack of symmetry, I'd say. Any hope that head would be updated ? – Ciprian Tomoiagă Jan 09 '23 at 10:41
  • 1
    @CiprianTomoiagă, some do like I said. You could request that feature be added to the maintainer of the `head` implementation you're using. We can request POSIX specify it, which as long as a majority of implementations already implement it, would likely be accepted. – Stéphane Chazelas Jan 09 '23 at 10:47
2

You can use the following way to remove first N lines and last M lines.

With N=5, M=7 and file test.txt:

sed -n -e "6,$(($(wc -l < test.txt) - 7))p" test.txt

The command prints all lines from N+1 to LastLine-M.

Another option is to use python:

python -c 'import sys;print "".join(sys.stdin.readlines()[5:-7]),' < test.txt

python3:

python -c 'import sys;print("".join(sys.stdin.readlines()[5:-7]))' < test.txt

To override the existing file:

python -c 'import sys;print("".join(sys.stdin.readlines()[5:-7]))' < test.txt > temp.txt && mv temp.txt test.txt
jofel
  • 26,513
  • 6
  • 65
  • 92
1

You can remove the last M (here M=100) lines from a file with:

head -$(($(wc -l < foo.txt) - 100)) foo.txt > temp.txt
make
  • 11
  • 1