用用户指定的替换字符串替换sed

时间:2015-03-02 22:12:03

标签: regex linux bash sed

substitution commandsed的一般形式是:

s/regexp/replacement/flags

其中' /'字符可以被任何其他单个字符统一替换。但是当替换字符串由环境变量输入并且可能包含任何可打印字符时,如何选择此分隔符?有没有一种直接的方法来使用bash转义变量中的分隔符?

这些值来自受信任的管理员,所以安全性不是我主要关注的问题。 (换句话说,请不要回答:"永远不要这样做!")尽管如此,我无法预测替换字符串中需要出现哪些字符。

4 个答案:

答案 0 :(得分:1)

您可以将控制字符用作正则表达式分隔符,如下所示:

s^Aregexp^Areplacement^Ag

其中^A CTRL v a 压在一起。

或者使用awk并且不要担心分隔符:

awk -v s="search" -v r="replacement" '{gsub(s, r)} 1' file

答案 1 :(得分:1)

以下是使用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部分中{1}}也是。例如。当你在$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}/')
  • 或通过命令行参数
  • 将变量传递给perl
final=$(echo "$string" | perl -spe 's/$f/$t/' -- -f="$from" -t="$to")

答案 2 :(得分:0)

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)在字符串模式中转义所需的char(需要一个预处理来转义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

答案 3 :(得分:0)

来自man sed

\cregexpc  
          Match lines matching the regular expression regexp.  The  c  may  be  any
          character.

使用路径时,我经常使用#作为分隔符:

sed s\#find/path#replace/path#

无需使用丑陋的/转义\/