24

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?

3

3 Answers 3

31

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}'
5
  • 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
    Commented Nov 21, 2014 at 0: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. Commented Nov 21, 2014 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') Commented Jan 6, 2023 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 ? Commented Jan 9, 2023 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. Commented Jan 9, 2023 at 10:47
3

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
2

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

head -$(($(wc -l < foo.txt) - 100)) foo.txt > temp.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .