The simplest solution would a combination of head
and tail
:
# hf_filter - remove a header and footer of fixed length from the input
$ hf_filter () { tail -n +$(($1 + 1)) | head -n -$2; }
$ hf_filter 14 2 < old.txt > new.txt
However, this requires GNU head
, as the standard version requires a positive integer as the argument for the -n
option.
A solution to this problem requires buffering $last
lines of output or prior knowledge of the length of the input. (GNU head
does the buffering for you.) A standard awk
solution might look like
awk -v h=14 -v t=2 'NR > h {buf[NR]=$0; s=NR-t} s in buf {print buf[s]; delete buf[s]}' old.txt > new.txt
The delete buf[s]
isn't strictly necessary, but I think it should keep the memory usage constant (although I don't really know how awk
manages memory allocations internally).
If you don't mind reading the input twice, you can get the input length if you don't already know it.
# Quotes are necessary; wc outputs leading spaces that break the assignment otherwise
awk -v n="$(wc -l < old.txt)" h=14 t=2 'NR > h && NR < n - t' old.txt > new.txt