166

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
  • 3,851
  • 2
  • 27
  • 42
Nicholas M T Elliott
  • 3,435
  • 2
  • 18
  • 15

8 Answers8

254

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).

Riccardo
  • 977
  • 10
  • 22
Joe Enos
  • 38,150
  • 11
  • 77
  • 129
  • 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
28

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
  • 116,304
  • 97
  • 251
  • 314
Mike DeMaria
  • 451
  • 4
  • 3
13

A simple solution using awk:

awk 'NR > 2 { print }' file.name
janm
  • 17,422
  • 1
  • 41
  • 60
  • 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
  • 7
    `{ 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
  • 67,570
  • 9
  • 102
  • 136
7

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

Jim Lewis
  • 41,827
  • 6
  • 83
  • 95
  • 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
  • 33,483
  • 8
  • 75
  • 107
  • @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
-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
  • 24,301
  • 10
  • 49
  • 75
  • 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
  • 307,646
  • 55
  • 250
  • 337
  • 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