jbord39
jbord39

Reputation: 169

Search and replace shell variable with multiline shell variable

I know there are lots of similar questions but, I guess because of the formatting of the search/replace variables they are not working for my situation.

The overall script I am working on will read a text file (using combinations of grep and awk) to create two shell variables, $find and $replace. $find is a single line string containing all manner of characters. $replace is a multiline string containing all manner of characters.

example:

echo "$find"

returns

type result input1 another_input random_input<10> / name

and

echo "$replace"

returns

.TAG name
result input1 random_input / name1
random_input<10> input1 another_input / name2
.NTAG

Now I just need to substitute $find with $replace. I have tried sed and perl but it fails.

Tried (among a lot of other stuff)

perl -e -i.bak "s/$find/$replace/g" text.file
perl -e -i.bak 's,"'$find'","'$replace'",g' text.file
perl -e -i.bak "s|$find|$replace|g" text.file

and

sed -i "s/$find/$replace/g" text.file

My guess is the problems are caused by some character in the string being interpreted as special characters.

Any help is appreciated!

Upvotes: 1

Views: 1144

Answers (3)

NeronLeVelu
NeronLeVelu

Reputation: 10039

one way with sed, quick and dirty so not bullet proof like the awk of @Ed Morton

find_sed="$( printf "%s" "${find}" | sed 's/[^0-9(){}]/\\&/g' )"
replace_sed="$( printf "%s" "${replace}" | sed "s/[&\\]/\\/g;s/\n/\\&/g' )"

sed "s/${find_sed}/${replace_sed}/g" YourFile
  • Could be a one line with internal substitution instead of variable, but more explicit like this
  • posix version ( --posix with GNU sed), if not posix, adapt [^0-9(){}] depending your special character that use a escape char for special meaning like \+\n\d\

Upvotes: 0

repzero
repzero

Reputation: 8412

restructure your variable to read

replace=".TAG name\nresult input1 random_input / name1\nrandom_input<10> input1 another_input / name2\n.NTAG"

or restructure it like this

replace='.TAG name\
    result input1 random_input / name1\
    random_input<10> input1 another_input / name2\
    .NTAG'

Also your delimiter is causing conflict with your variable replace characters since there are / in your variable

you can try # as your delimiter or any other char that is not in your variable

 sed "s#$find#$replace#g" text_file

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 203684

This will work for any values of find or replace:

$ cat file
foo
type result input1 another_input random_input<10> / name
bar

$ awk -v find="$find" -v replace="$replace" 's=index($0,find){$0=substr($0,1,s-1) replace substr($0,s+length(find))}1' file
foo
.TAG name
result input1 random_input / name1
random_input<10> input1 another_input / name2
.NTAG
bar

if find is always one whole line it can be simplified, e.g. this might be all you need:

$ awk -v find="$find" -v replace="$replace" '$0==find{$0=replace}1' file
foo
.TAG name
result input1 random_input / name1
random_input<10> input1 another_input / name2
.NTAG
bar

Upvotes: 2

Related Questions