sed, you could do:
One of the main problems with
ed (beside its syntax from another age) is error handling in script.
Basically, you have to think of it as
ed returns success if it successfully edited the file. But to be a successful edit, you have to have each commands address to be valid, each command to be successful (for instance, for the
s command, that means at least one substitution done).
So, if you want to check that the edit was successful in this case, it can be tricky.
To build up on @Sukminder's solution and attempt to cover the corner cases, one could write:
printf '%s\n' a a . 'g/\\$/s///' ',s/^/a/' 'g/^a$/+1,/./s/^a$//' \
'v/./d' 'g/^a/s///' '$d' w | ed -s the-file
g command would fail if the file was empty (because the default address range (
1,$) would be invalid, so we need first to add a line at the end of the file (with the
,s/\\$// would fail if there was no line ending in
\ so we need to run it only if there are such lines (
Here, instead of inserting a "xx" assuming it's not to be found in the input, we prepend "a" to each line and replace the lines to be removed with an empty line which we remove afterwards.
ed script will only return a non-zero exit status if it fails to write the file (
w command failing). Unfortunately, I've seen
ed implementations returning success when failing to write a file when the FS was full.
ed is best avoided. Nowadays, using
perl -pi.back is as portable and more reliable.