Reputation: 15000
The general form of the substitution command in sed is:
s/regexp/replacement/flags
where the '/' characters may be uniformly replaced by any other single character. But how do you choose this separator character when the replacement string is being fed in by an environment variable and might contain any printable character? Is there a straightforward way to escape the separator character in the variable using bash
?
The values are coming from trusted administrators so security is not my main concern. (In other words, please don't answer with: "Never do this!") Nevertheless, I can't predict what characters will need to appear in the replacement string.
Upvotes: 3
Views: 291
Reputation: 8181
From man sed
\cregexpc Match lines matching the regular expression regexp. The c may be any character.
When working with paths i often use #
as separator:
sed s\#find/path#replace/path#
No need to escape /
with ugly \/
.
Upvotes: 0
Reputation: 10039
2 options:
1) take a char not in the string (need a pre process on content check and possible char without warranty that a char is available)
# Quick and dirty sample using `'/_#@|!%=:;,-` arbitrary sequence
Separator="$( printf "%sa%s%s" '/_#@|!%=:;,-' "${regexp}" "${replacement}" \
| sed -n ':cycle
s/\(.\)\(.*a.*\1.*\)\1/\1\2/g;t cycle
s/\(.\)\(.*a.*\)\1/\2/g;t cycle
s/^\(.\).*a.*/\1/p
' )"
echo "Separator: [ ${Separator} ]"
sed "s${Separator}${regexp}${Separator}${replacement}${Separator}flag" YourFile
2) escape the wanted char in the string patterns (need a pre process to escape char).
# Quick and dirty sample using # arbitrary with few escape security check
regexpEsc="$( printf "%s" "${regexp}" | sed 's/#/\\#/g' )"
replacementEsc"$( printf "%s" "${replacement}" | sed 's/#/\\#/g' )"
sed 's#regexpEsc#replacementEsc#flags' YourFile
Upvotes: 0
Reputation: 63952
Here isn't (easy) solution for the following using the sed
.
while read -r string from to wanted
do
echo "in [$string] want replace [$from] to [$to] wanted result: [$wanted]"
final=$(echo "$string" | sed "s/$from/$to/")
[[ "$final" == "$wanted" ]] && echo OK || echo WRONG
echo
done <<EOF
=xxx= xxx === =====
=abc= abc /// =///=
=///= /// abc =abc=
EOF
what prints
in [=xxx=] want replace [xxx] to [===] wanted result: [=====]
OK
in [=abc=] want replace [abc] to [///] wanted result: [=///=]
sed: 1: "s/abc/////": bad flag in substitute command: '/'
WRONG
in [=///=] want replace [///] to [abc] wanted result: [=abc=]
sed: 1: "s/////abc/": bad flag in substitute command: '/'
WRONG
Can't resists: Never do this! (with sed). :)
Is there a straightforward way to escape the separator character in the variable using bash?
No, because you passing the strings from variables, you can't easily escape the separator character, because in "s/$from/$to/"
the separator can appear not only in the $to
part but in the $from
part too. E.g. when you escape the separator it in the $from
part it will not do the replacement at all, because will not find the $from
.
Solution: use something other as sed
1.) Using pure bash. In the above script instead of the sed
use the
final=${string//$from/$to}
2.) If the bash's substitutions are not enough, use something to what you can pass the $from
and $to
as variables.
as @anubhava already said, can use: awk -v f="$from" -v t="$to" '{gsub(f, t)} 1' file
or you can use perl
and passing values as environment variables
final=$(echo "$string" | perl_from="$from" perl_to="$to" perl -pe 's/$ENV{perl_from}/$ENV{perl_to}/')
final=$(echo "$string" | perl -spe 's/$f/$t/' -- -f="$from" -t="$to")
Upvotes: 1
Reputation: 785481
You can use control character as regex delimiters also like this:
s^Aregexp^Areplacement^Ag
Where ^A
is CTRLva pressed together.
Or else use awk
and don't worry about delimiters:
awk -v s="search" -v r="replacement" '{gsub(s, r)} 1' file
Upvotes: 1