I am trying to find out if it is possible to edit a file in a single sed command without manually streaming the edited content into a new file and
You can also use the redirection operator <>
to open the file to read and write:
sed 's/foo/bar/g' file 1<> file
See it live:
$ cat file
hello
i am here # see "here"
$ sed 's/here/away/' file 1<> file # Run the `sed` command
$ cat file
hello
i am away # this line is changed now
From Bash Reference Manual → 3.6.10 Opening File Descriptors for Reading and Writing:
The redirection operator
[n]<>word
causes the file whose name is the expansion of word to be opened for both reading and writing on file descriptor n, or on file descriptor 0 if n is not specified. If the file does not exist, it is created.
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt
Should preserve all hardlinks, since output is directed back to overwrite the contents of the original file, and avoids any need for a special version of sed.
You could use vi
vi -c '%s/foo/bar/g' my.txt -c 'wq'
You didn't specify what shell you are using, but with zsh you could use the =( )
construct to achieve this. Something along the lines of:
cp =(sed ... file; sync) file
=( )
is similar to >( )
but creates a temporary file which is automatically deleted when cp
terminates.
sed supports in-place editing. From man sed
:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)
Example:
Let's say you have a file hello.txt
with the text:
hello world!
If you want to keep a backup of the old file, use:
sed -i.bak 's/hello/bonjour' hello.txt
You will end up with two files: hello.txt
with the content:
bonjour world!
and hello.txt.bak
with the old content.
If you don't want to keep a copy, just don't pass the extension parameter.
Note that on OS X you might get strange errors like "invalid command code" or other strange errors when running this command. To fix this issue try
sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
This is because on the OSX version of sed
, the -i
option expects an extension
argument so your command is actually parsed as the extension
argument and the file path is interpreted as the command code. Source: https://stackoverflow.com/a/19457213