views:

165

answers:

8

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
A: 

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

tommieb75
But Nicholas doesn't know N in advance....
Jim Lewis
@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....
tommieb75
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
tommieb75
@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
@Jim: gotcha!!! I aint a GNU zealot that's for sure ;) Thanks for the heads up....
tommieb75
@tommie: But this is `tail`...shouldn't that be "bottoms up"? (Ba-dum TISH! Thank you, I'll be here all week...)
Jim Lewis
@Jim: LOL!!!! couldn't agree more...aye... bottoms up alrighty... :)
tommieb75
+1  A: 

tail +n filename will start output with the n-th line of filename, so tail +3 filename should do what you want.

Jim Lewis
+11  A: 

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 -n +3 should be what you're looking for.

Joe Enos
Oddly, my man page doesn't list the option, but it works just fine - thanks!
Nicholas M T Elliott
@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
+3  A: 

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
Mike DeMaria
A: 

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
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
@janm: You are all right. Other answers are just better. I feel embarrass. :-p
NawaMan
+2  A: 

A simple solution using awk:

awk 'NR > 2 { print }' file.name
janm
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
A: 

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
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
yes i misread the question. thought he is ask for all but last 2 lines.
ghostdog74
+1  A: 

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

lhf