How to obtain inverse behavior for `tail` and `head`?
Solution 1
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
.
Solution 2
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.
Solution 3
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.
Solution 4
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
Solution 5
{ 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.
Related videos on Youtube
Comments
-
chrisjlee almost 2 years
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. -
Stéphane Gimenez almost 13 years@fred: Strange indeed… (same with 8.12 here).
-
chrisjlee almost 13 yearsIs this operation destructive? As i want it to copy the inverse of the first two lines of the document to another?
-
Stéphane Gimenez almost 13 years@Chris: No, they just print the result on their "standard output", which is usually connected to the terminal. I've added some details on how to redirect the output to some files.
-
l0b0 about 11 years
head -n -2
is not POSIX compatible. -
SirMarv.....TheBinaryTechie almost 10 years
head -n -2 foo.txt
sayshead: illegal line count -- -2
-
Stéphane Chazelas about 9 yearsOn 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).
-
Wildcard over 7 yearsWhy 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.