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.
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.
You can use this to strip the first two lines:
tail -n +3 foo.txt
and this to strip the last two lines, if your implementation of head supports it:
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.
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.
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.
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 01:16
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
{ 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.
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'
Or:
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).
Or:
awk 'NR>3 {print l[NR%3]}; {l[NR%3]=$0}'
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)
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"
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)
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!
\n".. It works for all negative integers other than-n -0which returns nothing at all, just as-n 0would (using: head (GNU coreutils) 7.4) ... However when a trailing\nis present,-n -0does print as might be expected from the-, ie. it prints the entire file... So it does work for all non-zero negative values.. but-0fails when there is no trailing\n– Peter.O Aug 16 '11 at 06:16head -n -2is not POSIX compatible. – l0b0 May 15 '13 at 13:56head -n -2 foo.txtsayshead: illegal line count -- -2– gravitation Jul 10 '14 at 16:45