Wednesday, January 27, 2010

Sed - save changes to same file


Sed receives text input, either from stdin or from a file, performs certain operations on specified lines(or all lines) of the input, one line at a time, then outputs the result to stdout or to a file. Today I am going to show how we can use sed to do some operation on a file (mainly substitute, which is the most popular with sed) and write back the results to the same file.

Input file:

$ cat file.txt
port:9903
os-version:VERSION
codename:hardy
status:active

Lets try to replace the word 'VERSION' in the above file with '8.04'

$ sed 's/VERSION/8.04/' file.txt
port:9903
os-version:8.04
codename:hardy
status:active

So, be default sed outputs the result to 'stdout'.

Append or redirection to the same filename will be wrong !!

$ sed 's/VERSION/8.04/' file.txt > file.txt


Newer sed versions (e.g sed version 4.1.4), there is a useful command line option:

-i[SUFFIX], --in-place[=SUFFIX]

Description: edit files in place (makes backup if extension supplied)

Lets try this option:

$ cat file.txt
port:9903
os-version:VERSION
codename:hardy
status:active

$ sed -i 's/VERSION/8.04/' file.txt

$ cat file.txt
port:9903
os-version:8.04
codename:hardy
status:active

It worked; the result is printed to the same filename.

We can also mention the backup extension like this:

$ cat file.txt
port:9903
os-version:VERSION
codename:hardy
status:active

$ sed -i.bak 's/VERSION/8.04/' file.txt

$ cat file.txt
port:9903
os-version:8.04
codename:hardy
status:active

The original content of the input file is backed up here:

$ cat file.txt.bak
port:9903
os-version:VERSION
codename:hardy
status:active

With older version of 'sed' editor (where this -i option is absent), we can write the result to a temporary file and then in the next step we can move the temporary file back to the original file like this:

$ cat file.txt
port:9903
os-version:VERSION
codename:hardy
status:active

$ sed 's/VERSION/8.04/' file.txt > file.txt.tmp
$ mv file.txt.tmp file.txt

And to work with more number of files (say perform the same replacement as above in all the .cfg files in current directory, including sub-directory)

for file in $(find . -name "*.cfg")
do
echo "Replacing on : $file"
sed 's/VERSION/8.04/' $file > $file.tmp
mv $file.tmp $file
echo "Replacement done on : $file"
done

Related posts:

- Add Change Insert lines to file using sed
- Substitute character by position using sed
- Case insensitive search and replace using sed
- Accessing external variables in sed and awk
- Delete next few lines using sed

3 comments:

Stu said...

Hey, nice blog, I get a lot of enjoyment out of reading random snippets like these.

I noticed you didn't quote $file though:

for file in $(find . -name "*.cfg")
do
echo "Replacing on : $file"
sed 's/VERSION/8.04/' $file > $file.tmp
mv $file.tmp $file
echo "Replacement done on : $file"
done


This will break if $file ever has spaces or other abnormal characters.

probably just an oversight, but hey I'm in the mood to rant...

http://bash-hackers.org/wiki/doku.php/syntax/words
http://www.grymoire.com/Unix/Quote.html

Jadu Saikia said...

@Stu, thanks for the same.

obakesan said...

agreed ... nice to see there are still other command line dweebs out there (aside from me)

© Jadu Saikia www.UNIXCL.com