Ed and Ex are POSIX editors that can handle this task.
They are quite similar and in the solutions presented here
ex are 100% interchangeable1.
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
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
# Insert an empty line at the beginning
# 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: $
# 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
# Write the changes to the file and quit
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.