views:

30

answers:

3

I have a file named check.txt which has the below contents:

$ cat check.txt
~/bin/tibemsadmin -server $URL-user $USER -password $PASWRD
$

I have a main script where the values of $URL, $USER, $PASWRD are obtained from the main script. I want to use the SED utility to replace the $URL, $USER, $PASWRD to the actual values in the check.txt.

I am trying like this but it fails.

emsurl=tcp://myserver:3243
emsuser=test
emspasswd=new
sed s/$URL/${emsurl}/g check.txt >> check_new.txt
sed s/$USER/${emsuser}/g check.txt_new.txt >> check_new_1.txt
sed s/PASWRD/${emspasswd}/g check_new_1.txt >> final.txt

My final.txt output is desired as below:

~/bin/tibemsadmin -server tcp://myserver:3243 -user test -password new

Could you please help me?

+2  A: 

You have to be rather careful with your use of quotes. You also need to learn how to do multiple operations in a single pass, and/or how to use pipes.

emsurl=tcp://myserver:3243
emsuser=test
emspasswd=new
sed -e "s%\$URL%${emsurl}%g" \
    -e "s%\$USER%${emsuser}%g" \
    -e "s%\$PASWRD%${emspasswd}%g" check.txt >final.txt

Your problem is that the shell expanded the '$URL' in your command line (probably to nothing), meaning that sed got to see something other than what you intended. By escaping the $ with the \, sed gets to see what you intended.

Note that I initially used / as the separator in the substitute operations; however, as DarkDust rightly points out, that won't work since there are slashes in the URLs. My normal fallback character is % - as now shown - but that can appear in some URLs and might not be appropriate. I'd probably use a control character, such as control-A, if I needed to worry about that - or I'd use Perl which would be able to play without getting confused.

You can also combine the three separate -e expressions into one with semi-colons replacing them. However, I prefer the clarity of the three operations clearly separated.

Jonathan Leffler
You need to choose a different delimiter, `/` is used in the replacement text.
DarkDust
@DarkDust - good catch - you can tell I did not perform the test...
Jonathan Leffler
Dear Jon,DarkDust and Steve. Thanks a lot for your help. I have now understood where I am going wrong. Thank you very much.
Varun
+2  A: 

You could take a slightly different approach by modifying your main script as follows :-

export URL="tcp://myserver:3243"
export USER=test
export PASWRD=new
. ./check.txt

This sets up the variables and then runs check.txt within the context of your main script

Steve Weet
+1 for thinking out of the box - but not helping him learn how to use `sed` properly. He'd need to upgrade the script to deal with unset variables, too (`${URL:?}` as a basic minimum). Also, there's no need to use `. ./check.txt`; it can be run simply as `./check.txt` or `sh check.txt` if the variables are exported. If the variables were merely set, then the `.` command would be needed.
Jonathan Leffler
Thanks Jonathan. Still teaching me things 20 years later!
Steve Weet
+1  A: 

Although you don't say what's failing I guess I see the problems.

I suggest you do this:

sed "s|\$URL|${emsurl}|g"

That is, the first $ needs to be escaped because you want it literally. Then, instead of / I suggest you use | (pipe) as delimiter since it's not used in your strings. Finally, use " to ensure the content is interpreted as string by the shell.

You can then pipe everything together to not need any temporary files:

sed "s|\$URL|${emsurl}|g" | sed "s|\$USER|${emsuser}|g" | sed "s|\$PASSWRD|${emspasswd}|g"
DarkDust
You can do it all in one sed command by using repeated '-e' options, which is considerably more efficient. But using pipes is much preferable to using explicit intermediate files (which were not cleaned up in the original).
Jonathan Leffler