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?