I find myself trying to "edit" a file in-place quite a lot in my shell. Say, I want to remove all lines in words.txt that contain the letter e. Then, I would execute:
$ grep -v e words.txt > words-without-e.txt
$ mv words-without-e.txt words.txt
Many people are confused why they are left with an empty file when executing the following (I am not):
$ grep -v e words.txt > words.txt
grep: words.txt: input file is also the output
Some commands have special flags for in-place behaviour, like --in-place (see sed(1)) to allow this. It's possible to use sponge(1), but this requires me to type the file name twice, which I don't like.
$ grep -v e words.txt | sponge words.txt
I have defined a function that I find handy:
function inplace { "${@:2}" < "$1" | sponge $1 }
With it, I can now do:
$ inplace words.txt grep -v e
I know that this is limited to "stream processing", i.e. commands that take standard input, process it, and produce standard output. But many commands do.
Maybe I looked in the wrong places, but I haven't stumbled across a similar definition yet, especially given how often the question about in-place editing comes up.
- Is there a common utility that serves the same purpose?
- Have you defined such a function? How does your definition look like? What did you call it?
- Why does this not come up more often? Or did I just miss it?
spongeitself doesn't provide the wrapper functionality... But it's also impossible to make a really generic wrapper, because an arbitrary tool might edit the given file in-place itself, and not print to stdout. Using the wrapper with one like that might be problematic. Also there's the question of caching the data to memory vs. to a temporary file, and overwriting the target in-place vs. creating a new file with the same name... (not sure what sponge does)inplace() { "${@:2}" < "$1" | sponge "$1" }inplace() { "${@:2}" < "$1" | sponge -- "$1"; }to deal with arbitrary file paths. Orinplace() (file="${1?}"; shift; <"$file" "$@" | sponge -- "$file")to avoid that ksh93ism. Setting thepipefailoption in there would also be useful to report failure of the command (in any case, the file is lost if the command fails).