Unix – Updating a file with sed

sedunix

I am trying to find and replace a couple of words in a file and try to execute that file as a .sql file

sed -e "s/wordToFind1/UnixFile/g" Check.sql;
sed -e "s/wordToFind2/WordToReplace2/g" Check.sql;

In the above, I am trying to find wordToFind1 and replace it with a UnixFile : /usr/bin/try.txt
and then, trying to find wordToFind2 and replace it with another word : tablename

Before sed – Check.sql :

servermonitor on
spool wordToFind1
select * from wordToFind2

After sed – Check.sql :

servermonitor on
spool /usr/bin/try.txt
select * from tablename

Once the above changes are done, I am trying to execute the sql file. Please help!!!

Best Answer

You have some problems to solve here.

Using slashes (/) inside s///

First, you want to replace wordToFind1 with /usr/bin/try.txt. It will not work with the s/// command at first, because the replacing string contains /. It would to a very weird command!

sed -e 's/wordToFind1//usr/bin/try.txt/' Check.sql

Sed will think that the command is s/wordToFind1// with some flags (such as u) and other commands following, but it makes no sense and it will generate an error. A solution is to escape each / from /usr/bin/try.txt with \:

$ sed -e 's/wordToFind1/\/usr\/bin\/try.txt/' Check.sql
servermonitor on
spool /usr/bin/try.txt
select * from wordToFind2

This is clumsy, however. When you have a lot of / in your replacing string (or even in the replaced string), a better solution IMHO is to use another character as the delimiters of s///. Not everybody knows it is possible, but one can use any other char instead of / as the delimiter of s///. In this case, you can use as much / as you want inside your expressions without needing of escaping them. In the example below, I am using # instead of /, so the slashes from /usr/bin/try.txt cause no trouble:

$ sed -e 's#wordToFind1#/usr/bin/try.txt#' Check.sql
servermonitor on
spool /usr/bin/try.txt
select * from wordToFind2

Using more than one s/// command

Solved that, you should replace wordToFind2 too. This is easy: just pass another -e command in the same sed invocation:

$ sed -e 's#wordToFind1#/usr/bin/try.txt#' -e 's/wordToFind2/tablename/' Check.sql
servermonitor on
spool /usr/bin/try.txt
select * from tablename

(Another option is to add more than one option in one string only, separarated by semicolons:

$ sed -e 's#wordToFind1#/usr/bin/try.txt#;s/wordToFind2/tablename/' Check.sql
servermonitor on
spool /usr/bin/try.txt
select * from tablename

I find it very useful sometimes, with bigger sed scripts, but it is less readable as well).

Updating the input file with -i

Now, you need to update the Check.sql file. This is easy as well: just pass the -i flag to sed. This flag makes sed update the original file. Also, this flag can receive a parameter, that is an extension to be added to a backup file with the original content. In this case, I will use the .bkp extension. See the results:

$ sed -i.bkp -e 's#wordToFind1#/usr/bin/try.txt#' -e 's/wordToFind2/tablename/' Check.sql
$ cat Check.sql
servermonitor on
spool /usr/bin/try.txt
select * from tablename

Now, Check.sql changed. Also, there is a Check.sql.bkp with the old content:

$ cat Check.sql.bkp 
servermonitor on
spool wordToFind1
select * from wordToFind2

This may be helpful if something goes wrong.