你也可以像这样使用控制字符作为正则表达式定界符:
s^Aregexp^Areplacement^Ag
当你按下CTRLva时,^A
就会出现。
或者使用awk
,不必担心分隔符:
awk -v s="search" -v r="replacement" '{gsub(s, r)} 1' file
以下内容使用 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
什么会被打印出来
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
无法抗拒:永远不要这样做!(使用sed)。:)
有没有一种简单的方法在bash中使用变量转义分隔符字符?
没有,因为你正在从变量传递字符串,你不能轻松地转义分隔符字符,因为在"s/$from/$to/"
中,分隔符不仅可以出现在$to
部分,还可以出现在$from
部分。例如,当你在$from
部分中转义分隔符时,它根本不会替换任何内容,因为找不到$from
。
解决方案:使用其他工具而不是sed
1.) 使用纯bash。在上面的脚本中,不要使用sed
,而是使用
final=${string//$from/$to}
2.) 如果bash的替换不够用,可以使用一些东西将$from
和$to
作为变量传递。
如@anubhava所说,可以使用:awk -v f="$from" -v t="$to" '{gsub(f, t)} 1' file
或者您可以使用perl
并将值作为环境变量传递
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")
来自man sed
\cregexpc Match lines matching the regular expression regexp. The c may be any character.
在处理路径时,我经常使用#
作为分隔符:
sed s\#find/path#replace/path#
没必要用丑陋的 \/
转义 /
。
两个选项:
1)取一个不在字符串中的字符(需要对内容进行预处理检查并可能使用无保修的字符,不能保证字符可用)
# 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) 在字符串模式中转义所需的字符(需要预处理来转义字符)。
# 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