Note that contrary to the "wc" based solution I gave which would work on GNU systems, the above will only work correctly with zsh if the last line contains NUL characters. Also, it won't work correctly if the last line is not NL terminated.
–
Stephane ChazelasAug 29 '12 at 15:54

What you want is truncate the file just before the last line without having to read the file entirely.

truncate -s -"$(tail -n1 file | wc -c)" file

That's assuming the file is not currently being written to.

truncate is part of the GNU coreutils (so generally found on recent Linux distributions) and is not a standardized Unix or POSIX command. Many "dd" implementations can be used to truncate a file as well.

Using tail + truncate would indeed be a more efficient solution. Naturally, to allow the OP to retrieve the contents of the last line tail -n should be called separately and stored in a var. You can then use ${#VAR} + 1 as the truncation size.
–
Shawn ChinAug 29 '12 at 12:39

There seems to be an extra - preceding the tail/wc combo. Also, you could use the -r option (use the given file's size) here: truncate -r <(tail -n1 file) file if you don't mind the bashism.
–
chepnerAug 29 '12 at 13:02

1

Process substitution is a kshism (also supported by zsh and bash). It won't work because <(tail -n1 file) is a pipe and because we want to shave off that many files, not truncate the file to the same size as its last line.
–
Stephane ChazelasAug 29 '12 at 15:58