sed edit file in place

UnixSedSolaris

Unix Problem Overview


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 then renaming the new file to the original file name. I tried the -i option but my Solaris system said that -i is an illegal option. Is there a different way?

Unix Solutions


Solution 1 - Unix

The -i option streams the edited content into a new file and then renames it behind the scenes, anyway.

Example:

sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename

while on macOS you need:

sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename

Solution 2 - Unix

On a system where sed does not have the ability to edit files in place, I think the better solution would be to use perl:

perl -pi -e 's/foo/bar/g' file.txt

Although this does create a temporary file, it replaces the original because an empty in place suffix/extension has been supplied.

Solution 3 - Unix

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

Solution 4 - Unix

The following works fine on my mac

sed -i.bak 's/foo/bar/g' sample

We are replacing foo with bar in sample file. Backup of original file will be saved in sample.bak

For editing inline without backup, use the following command

sed -i'' 's/foo/bar/g' sample

Solution 5 - Unix

One thing to note, sed cannot write files on its own as the sole purpose of sed is to act as an editor on the "stream" (ie pipelines of stdin, stdout, stderr, and other >&n buffers, sockets and the like). With this in mind you can use another command tee to write the output back to the file. Another option is to create a patch from piping the content into diff.

Tee method

sed '/regex/' <file> | tee <file>

Patch method

sed '/regex/' <file> | diff -p <file> /dev/stdin | patch

UPDATE:

Also, note that patch will get the file to change from line 1 of the diff output:

Patch does not need to know which file to access as this is found in the first line of the output from diff:

$ echo foobar | tee fubar

$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin
*** fubar	2014-03-15 18:06:09.000000000 -0500
--- /dev/stdin	2014-03-15 18:06:41.000000000 -0500
***************
*** 1 ****
! foobar
--- 1 ----
! fubar

$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin | patch
patching file fubar

Solution 6 - Unix

Versions of sed that support the -i option for editing a file in place write to a temporary file and then rename the file.

Alternatively, you can just use ed. For example, to change all occurrences of foo to bar in the file file.txt, you can do:

echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt

Syntax is similar to sed, but certainly not exactly the same.

Even if you don't have a -i supporting sed, you can easily write a script to do the work for you. Instead of sed -i 's/foo/bar/g' file, you could do inline file sed 's/foo/bar/g'. Such a script is trivial to write. For example:

#!/bin/sh
IN=$1
shift
trap 'rm -f "$tmp"' 0
tmp=$( mktemp )
<"$IN" "$@" >"$tmp" && cat "$tmp" > "$IN"  # preserve hard links

should be adequate for most uses.

Solution 7 - Unix

You could use vi

vi -c '%s/foo/bar/g' my.txt -c 'wq'

Solution 8 - Unix

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.txtwith 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.

Solution 9 - Unix

If you are replacing the same amount of characters and after carefully reading “In-place” editing of files...

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.

Solution 10 - Unix

Like Moneypenny said in Skyfall: "Sometimes the old ways are best." Kincade said something similar later on.

$ printf ',s/false/true/g\nw\n' | ed {YourFileHere}

Happy editing in place. Added '\nw\n' to write the file. Apologies for delay answering request.

Solution 11 - Unix

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.

Solution 12 - Unix

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.

Solution 13 - Unix

Very good examples. I had the challenge to edit in place many files and the -i option seems to be the only reasonable solution using it within the find command. Here the script to add "version:" in front of the first line of each file:

find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;

Solution 14 - Unix

To resolve this issue on Mac I had to add some unix functions to core-utils following this.

brew install grep
==> Caveats
All commands have been installed with the prefix "g".
If you need to use these commands with their normal names, you
can add a "gnubin" directory to your PATH from your bashrc like:
  PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"

Call with gsed instead of sed. The mac default doesn't like how grep -rl displays file names with the ./ preprended.

~/my-dir/configs$ grep -rl Promise . | xargs sed -i 's/Promise/Bluebirg/g'

sed: 1: "./test_config.js": invalid command code .

I also had to use xargs -I{} sed -i 's/Promise/Bluebirg/g' {} for files with a space in the name.

Solution 15 - Unix

In case you want to replace stings contain '/',you can use '?'. i.e. replace '/usr/local/bin/python' with '/usr/bin/python3' for all *.py files.

find . -name \*.py -exec sed -i 's?/usr/local/bin/python?/usr/bin/python3?g' {} \;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionamphibientView Question on Stackoverflow
Solution 1 - UnixchorobaView Answer on Stackoverflow
Solution 2 - UnixSteveView Answer on Stackoverflow
Solution 3 - UnixdiadyneView Answer on Stackoverflow
Solution 4 - Unixminhas23View Answer on Stackoverflow
Solution 5 - UnixDwight SpencerView Answer on Stackoverflow
Solution 6 - UnixWilliam PursellView Answer on Stackoverflow
Solution 7 - UnixmenchView Answer on Stackoverflow
Solution 8 - UnixSergio A.View Answer on Stackoverflow
Solution 9 - UnixfedorquiView Answer on Stackoverflow
Solution 10 - UnixjlettvinView Answer on Stackoverflow
Solution 11 - UnixThorView Answer on Stackoverflow
Solution 12 - UnixJJMView Answer on Stackoverflow
Solution 13 - UnixRobertView Answer on Stackoverflow
Solution 14 - UnixClark BenhamView Answer on Stackoverflow
Solution 15 - UnixMark YuanView Answer on Stackoverflow