Ed and Ex are POSIX editors that can handle this task.
They are quite similar and in the solutions presented here
ed
and ex
are 100% interchangeable1.
General solution
printf '%s\n' a '' . 0a '' . '?.?+1,$d' '1,/./-1d' w q | ex -s file
If the file is known to have empty lines at the beginning and end
printf '%s\n' '?.?+1,$d' '1,/./-1d' w q | ex -s file
If you actually meant blank2 lines
printf '%s\n' a '' . 0a '' . '?[^[:blank:]]?+1,$d' '1,/[^[:blank:]]/-1d' w q | ex -s file
Explanation and breakdown
The manual is always the best explanation, but here is an overview:
Ed and Ex always start with the last line selected — so if we were to issue an
unadorned d
(delete command), it would delete the last line —
and they can look for lines matching regular expressions.
Some commands take addresses ("line numbers"), e.g. 3,6d
deletes from
lines 3 to 6.
/regex/
looks ahead for the first line matching "regex".
?regex?
looks behind for the first line matching "regex".
Guess what? A regex can be an address too.
# Insert an empty line at the end
a
.
Insert an empty line at the beginning
0a
.
Delete from line L1 up to line L2, where
L1 is the line below the last non-empty line: ?.?+1
L2 is the last line: $
?.?+1,$d
Delete from line L3 up to line L4, where
L3 is the first line: 1
L4 is the line above the first non-empty line: /./-1
1,/./-1d
Write the changes to the file and quit
w
q
Why do we need to temporarily add two empty lines for the general
solution? Because otherwise 1,/./-1d
would always delete the first line and
?.?+1,$d
the last, even if not empty.
1: But IIRC a clean Debian installation lacks Ed, so I'm going with Ex.
2: I.e., lines that are visually empty but may contain spaces and tabs.
1:
are not actually there? – RomanPerekhrest Nov 14 '19 at 15:05