Is there a way to head/tail a document and get the reverse output; because you don't know how many lines there are in a document?

I.e. I just want to get everything but the first 2 lines of foo.txt to append to another document.

10 Answers 10


You can use this to strip the first two lines:

tail -n +3 foo.txt

and this to strip the last two lines:

head -n -2 foo.txt

(assuming the file ends with \n for the latter)

Just like for the standard usage of tail and head these operations are not destructive. Use >out.txt if you want to redirect the output to some new file:

tail -n +3 foo.txt >out.txt

In the case out.txt already exists, it will overwrite this file. Use >>out.txt instead of >out.txt if you'd rather have the output appended to out.txt.

| improve this answer | |
  • 3
    re "head, when file ends with \n".. It works for all negative integers other than -n -0 which returns nothing at all, just as -n 0 would (using: head (GNU coreutils) 7.4) ... However when a trailing \n is present, -n -0 does print as might be expected from the -, ie. it prints the entire file... So it does work for all non-zero negative values.. but -0 fails when there is no trailing \n – Peter.O Aug 16 '11 at 6:16
  • @fred: Strange indeed… (same with 8.12 here). – Stéphane Gimenez Aug 16 '11 at 9:21
  • Is this operation destructive? As i want it to copy the inverse of the first two lines of the document to another? – chrisjlee Aug 16 '11 at 14:29
  • 8
    head -n -2 is not POSIX compatible. – l0b0 May 15 '13 at 13:56
  • 1
    head -n -2 foo.txt says head: illegal line count -- -2 – gravitation Jul 10 '14 at 16:45

If you want all but the first N-1 lines, call tail with the number of lines +N. (The number is the number of the first line you want to retain, starting at 1, i.e. +1 means start at the top, +2 means skip one line and so on).

tail -n +3 foo.txt >>other-document

There's no easy, portable way to skip the last N lines. GNU head allows head -n +N as a counterpart of tail -n +N. Otherwise, if you have tac (e.g. GNU or Busybox), you can combine it with tail:

tac | tail -n +3 | tac

Portably, you can use an awk filter (untested):

awk -vskip=2 '{
    lines[NR] = $0;
    if (NR > skip) print lines[NR-skip];
    delete lines[NR-skip];

If you want to remove the last few lines from a large file, you can determine the byte offset of the piece to truncate then perform the truncation with dd.

total=$(wc -c < /file/to/truncate)
chop=$(tail -n 42 /file/to/truncate | wc -c)
dd if=/dev/null of=/file/to/truncate seek=1 bs="$((total-chop))"

You can't truncate a file in place at the beginning, though if you need to remove the first few lines of a huge file, you can move the contents around.

| improve this answer | |
  • On some systems (like modern Linux), you can truncate (collapse) a file in place at the beginning, but usually only by an amount that is multiple of the FS block size (so not really useful in this case). – Stéphane Chazelas May 19 '15 at 16:49

From the tail man page (GNU tail, that is):

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

Thus, the following should append all but the first 2 lines of somefile.txt to anotherfile.txt:

tail --lines=+3 somefile.txt >> anotherfile.txt
| improve this answer | |

To remove the first n lines GNU sed can be used. For example if n = 2

sed -n '1,2!p' input-file

The ! mean "exclude this interval". As you can imagine, more complicated result can be obtained, for example

sed -n '3,5p;7p'

that will show line 3,4,5,7. More power come from use of regular expressions instead of addresses.

The limitation is that the lines numbers must be known in advance.

| improve this answer | |
  • 1
    Why not just sed 1,2d? Simpler is usually better. Also, nothing in your examples is specific to GNU Sed; your commands all use standard POSIX features of Sed. – Wildcard Oct 12 '16 at 1:16
{   head -n2 >/dev/null
    cat  >> other_document
}   <infile

If <infile is a regular, lseek()-able file, then yes, by all means, feel free. The above is a fully POSIXly supported construct.

| improve this answer | |

You can use diff to compare the output of head/tail to the original file and then remove what is the same, therefore getting the inverse.

diff --unchanged-group-format='' foo.txt <(head -2 foo.txt)
| improve this answer | |

While tail -n +4 to output the file starting at the 4th line (all but the first 3 lines) is standard and portable, its head counterpart (head -n -3, all but the last 3 lines) is not.

Portably, you'd do:

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


sed -ne :1 -e '1,3{N;b1' -e '}' -e 'P;N;D'

(beware that on some systems where sed has a pattern space of limited size, that doesn't scale to large values of n).


awk 'NR>3 {print l[NR%3]}; {l[NR%3]=$0}'
| improve this answer | |

My approach is similar to Gilles but I instead just reverse the file with cat and pipe that with the head command.

tac -r thefile.txt | head thisfile.txt (replaces files)

| improve this answer | |

Hope I clearly understood your need.

You've several ways to complete your request :

tail -n$(expr $(cat /etc/passwd|wc -l) - 2) /etc/passwd

Where /etc/passwd is your file

The 2nd solution may be usefull if you have huge file:

my1stline=$(head -n1 /etc/passwd)
my2ndline=$(head -n2 /etc/passwd|grep -v "$my1stline")
cat /etc/passwd |grep -Ev "$my1stline|$my2ndline"
| improve this answer | |

Solution for BSD (macOS):

Remove first 2 lines:

tail -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

Remove last 2 lines:

head -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

...not very elegant but gets the job done!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.