sed中 replace命令的一般forms是:
s/regexp/replacement/flags
其中“/”字符可以被任何其他单个字符统一replace。 但是,如果replacestring由环境variables提供并且可能包含任何可打印字符,那么如何select此分隔符? 有没有一种简单的方法来使用bash
转义variables中的分隔符?
值来自受信任的pipe理员,所以安全性不是我主要关心的。 (换句话说,请不要回答:“不要这样做!”)然而,我无法预测replacestring中需要显示哪些字符。
你可以使用控制字符作为正则表达式分隔符也是这样的:
s^Aregexp^Areplacement^Ag
其中^A
是CTRL v一起按下。
或者使用awk
,不要担心分隔符:
awk -vs="search" -vr="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
。
解决方案:使用其他的东西
1)使用纯粹的bash。 在上面的脚本中,而不是使用sed
final=${string//$from/$to}
2.)如果bash的替换不够用,可以使用$to
和$to
作为变量。
作为@anubhava已经说过,可以使用: awk -vf="$from" -vt="$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")
2个选项:
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