185

Given a text file of unknown length, how can I read, for example all but the first 2 lines of the file? I know tail will give me the last N lines, but I don't know what N is ahead of time.

So for a file

AAAA
BBBB
CCCC
DDDD
EEEE

I want

CCCC
DDDD
EEEE

And for a file

AAAA
BBBB
CCCC

I'd get just

CCCC
Adrian Heine
  • 4,051
  • 2
  • 30
  • 43
Nicholas M T Elliott
  • 3,643
  • 2
  • 19
  • 15
  • Does this answer your question? [How can I remove the first line of a text file using bash/sed script?](https://stackoverflow.com/questions/339483/how-can-i-remove-the-first-line-of-a-text-file-using-bash-sed-script) – cachius Dec 01 '22 at 13:09
  • This question already has answers [here](/q/339483) and [here](/q/604864). – cachius Dec 01 '22 at 13:10

9 Answers9

278

tail --help gives the following:

  -n, --lines=K            output the last K lines, instead of the last 10;
                           or use -n +K to output lines starting with the Kth
      

So to filter out the first 2 lines, -n +3 should give you the output you are looking for (start from 3rd):

tail -n +3
redseven
  • 849
  • 6
  • 11
Joe Enos
  • 39,478
  • 11
  • 80
  • 136
  • 2
    Oddly, my man page doesn't list the option, but it works just fine - thanks! – Nicholas M T Elliott Aug 18 '10 at 02:40
  • @Nicholas: Weird, I figured it would be standard documentation regardless of the OS. I pulled that from Cygwin inside Windows, so I don't know what it looks like in various Linux distros. Glad it worked. – Joe Enos Aug 18 '10 at 02:43
  • @NicholasMTElliott [man7](http://man7.org/linux/man-pages/man1/tail.1.html) lists it like Joe Enos' manpage, so it's likely to be a manpage version issue – Uli Köhler Oct 04 '16 at 17:18
  • @SteveJorgensen: I don't understand what your comment is referring to; no one seems to be suggesting to use `head` for this? – ruakh Sep 05 '19 at 19:52
  • 2
    Probably obvious to everyone but me, but +K is the _1-indexed_ Kth line, so e.g. `tail -n +1` is equivalent to `cat`. To get all but the first line, you need to do `tail -n +2`. – Lucas Wiman Apr 12 '23 at 21:08
29

Assuming your version of tail supports it, you can specify starting the tail after X lines. In your case, you'd do 2+1.

tail -n +3

[mdemaria@oblivion ~]$ tail -n +3 stack_overflow.txt
CCCC
DDDD
EEEE
Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
Mike DeMaria
  • 471
  • 4
  • 3
14

A simple solution using awk:

awk 'NR > 2 { print }' file.name
janm
  • 17,976
  • 1
  • 43
  • 61
  • One of us is confused. The questions says: "all but the first 2 lines of the file". How does that command not meet the requirement? – janm Aug 18 '10 at 01:08
  • 9
    `{ print }` is the default action, and can be omitted. – tripleee Apr 29 '14 at 11:40
10

Try sed 1,2d. Replace 2 as needed.

lhf
  • 70,581
  • 9
  • 108
  • 149
9

tail -n +linecount filename will start output at line linecount of filename, so tail -n +3 filename should do what you want.

Jim Lewis
  • 43,505
  • 7
  • 82
  • 96
  • This wouldn't work in my shell but `tail -n +17 filename` would. I use bash/ubuntu LTS – isomorphismes Aug 26 '12 at 07:52
  • 2
    @iso: Thanks for the heads-up -- older versions of `tail` accepted the syntax I used in my original answer, but now one needs to use the explicit `-n` option. I've updated my answer accordingly. – Jim Lewis Aug 26 '12 at 16:18
0

Use this, supposing the first sample is called sample1.dat then tail --lines=3 sample1.dat which would print all lines from the 3rd line to the last line.

For the second sample, again suppose it is called sample2.dat it would be tail --lines=-1 sample2.dat which would print the last line...

t0mm13b
  • 34,087
  • 8
  • 78
  • 110
  • @Jim: what's the difference with yours and mine?....same thing.... :o I was referring to the two sample data file inputs as per his question and showing how to achieve what he was looking for.... – t0mm13b Aug 18 '10 at 00:39
  • Ok... then why did he ask for the second sample and showed the result he wanted which is what I used 'tail --lines=-1'...... of course you can omit the filename completely and its still can act as a pipe... hmm – t0mm13b Aug 18 '10 at 00:48
  • @tommie: Oops, forget what I said about pipes...I must have been thinking of some other utility. But my point was that a single command,`tail +3 anyfile`, gives the desired results for the general case, while `tail --lines=N` requires knowing N in advance to give the desired result. – Jim Lewis Aug 18 '10 at 01:06
  • @tommie: But this is `tail`...shouldn't that be "bottoms up"? (Ba-dum TISH! Thank you, I'll be here all week...) – Jim Lewis Aug 18 '10 at 01:41
0

The head function supports this with negative numbers.

head --help

-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

For example, a positive number prints the first 2 lines.

 head -n +2

 AAAA
 BBBB

A negative number prints all except for the first 2 lines.

head -n -2

CCCC
DDDD
EEEE

Note that unlike with tail this does not require prior knowledge of the total number of lines in a file. It excludes the first 2 lines regardless of how many lines there are. Negative numbers for tail -n -2 can similarly be used to remove the last 2 lines of a file.

Note this uses GNU head version 8.22. This feature may not have been available at the original time of release. It is now available even if fairly old linux distros.

Tom Kelly
  • 1,458
  • 17
  • 25
  • 1
    Sadly on the Mac (here using macOS 12.6), head does not accept negative numbers like head -n -2 to skip that many lines at the start (it complains "illegal line count"). However while undocumented, tail -n +3 with a plus three does work for starting at line three (suggested in another answer). – Peter Cock Nov 03 '22 at 11:55
-1

I really don't know how to do it from just tail or head but with the help of wc -l (line count) and bash expression, you can achieve that.

tail -$(( $( wc -l $FILE | grep -Eo '[0-9]+' ) - 2 )) $FILE

Hope this helps.

NawaMan
  • 25,129
  • 10
  • 51
  • 77
  • 1
    This requires a complete pass over the file before running tail. If the file is greater than the size of memory this will be very inefficient. It does not handle files less than two lines. It does not handle the file changing size between the wc and the tail. – janm Aug 18 '10 at 01:18
  • 2
    @janm: You are all right. Other answers are just better. I feel embarrass. :-p – NawaMan Aug 18 '10 at 01:20
-1

using awk to get all but the last 2 line

awk 'FNR==NR{n=FNR}FNR<=n-3{print}' file file

awk to get all but the first 2 lines

awk 'NR>2' file

OR you can use more

more +2 file

or just bash

#!/bin/bash

i=0
while read -r line
do
  [[ $i > 1 ]] && echo "$line"
  ((i++))
done <"file"
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • Now this doesn't meet the requirement. The question says "all but the first 2 lines of the file" and gives two examples, each with a single file, where the first two lines are skipped and the remainder of the file is sent to stdout. That is not what this command does. – janm Aug 18 '10 at 01:14
  • yes i misread the question. thought he is ask for all but last 2 lines. – ghostdog74 Aug 18 '10 at 01:58