For all those little papers scattered across your desk
Right tool for the job people, right tool for the job
I’m referring to all the use of sed -i
spread wantonly on the internet, sans
appropriate caveats.
Background: most implementations of the
-i
flag allowsed
to edit files in place; by default, it edits standard in and writes to standard out, so you end up having to do<file sed ... >file.new && mv file.new file
. Trying to redirect back into the file (<file sed ... >file
) fails because the file is truncated beforesed
gets to read it!
The -i
flag is not specified by
POSIX, which makes it
non-portable. This isn’t such a big deal, except that different sed
s require
different arguments! GNU sed
edits in place, no argument provided. BSD sed
,
such as the one on macOS, requires a suffix:
file.suffix
and
the new contents in file
;So now, every sed -i
solution to a problem needs to at least
I don’t know about you, but I wonder if the solution to editing files in place is a lot simpler…
sed
for streams, ed
for filessed
stands for “stream editor.” It was designed based on the text-editor
ed
’s commands! ed
is built to edit files.
ed
(or the improved
POSIX-specified ex
);sed
is an option.I cannot emphasize this enough. Trying to use sed -i
in any kind of portable
anything is likely to break; worse was the thought that sed
should ever be
used for editing files! Use a text-editor: if you thought “I’m automating, I
don’t want to run a text-editor to automate,” well, remember:
ed
and ex
, anded
takes commands on standard in. It can be made silent with -s
, and the
argument is a file to edit. I ignore -p
for now because it isn’t useful for
scripting/automation. So, to script ed
, generate a list of commands and pipe
it in!
printf '%s\n' g/abc/d w q | ed -s file
That’s the most portable, but bash
users can probably do
ed -s file <<EOF
g/abc/d
w
q
EOF
There is quite a bit of flexibility here; the left-hand side could actually be
another program that generates ed
commands on standard out! It turns out,
this is what diff
does: in its default output mode, we have
These lines resemble
ed
subcommands to convertfile1
intofile2
. The line numbers before the action letters shall pertain tofile1
; those after shall pertain tofile2
. Thus, by exchanginga
ford
and reading the line in reverse order, one can also determine how to convertfile2
intofile1
. As ined
, identical pairs (wherenum1=num2
) are abbreviated as a single number.
And when we ask for the -e
output mode:
With the
-e
option, a script shall be produced that shall, when provided as input toed
, along with an appendedw
(write) command, convertfile1
intofile2
.
So now, you can probably write a patch
command you parse the output
from diff
, with maybe slight modification, and then pass it as input to ed
!