在我的bash脚本中,我有一个外部(从用户接收)字符串,我应该在sed模式中使用。

REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"

我如何转义$REPLACE字符串,以便它被sed安全地接受为文字替换?

注意:KEYWORD是一个哑子字符串,没有匹配等。不是用户提供的。


当前回答

使用awk -它更干净:

$ awk -v R='//addr:\\file' '{ sub("THIS", R, $0); print $0 }' <<< "http://file:\_THIS_/path/to/a/file\\is\\\a\\ nightmare"
http://file:\_//addr:\file_/path/to/a/file\\is\\\a\\ nightmare

其他回答

看来你问错问题了。我也问错了问题。错误的原因是第一句话的开头:“在我的bash脚本中…”。

我也有同样的问题,犯了同样的错误。如果您正在使用bash,则不需要使用sed来进行字符串替换(使用bash中内置的替换特性要干净得多)。

而不是像这样,例如:

function escape-all-funny-characters() { UNKNOWN_CODE_THAT_ANSWERS_THE_QUESTION_YOU_ASKED; }
INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A="$(escape-all-funny-characters 'KEYWORD')"
B="$(escape-all-funny-characters '<funny characters here>')"
OUTPUT="$(sed "s/$A/$B/g" <<<"$INPUT")"

你可以专门使用bash特性:

INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A='KEYWORD'
B='<funny characters here>'
OUTPUT="${INPUT//"$A"/"$B"}"

下面是我之前用过的一个AWK的例子。它是一个AWK,打印新的AWKS。AWK和SED相似,可能是一个很好的模板。

ls | awk '{ print "awk " "'"'"'"  " {print $1,$2,$3} " "'"'"'"  " " $1 ".old_ext > " $1 ".new_ext"  }' > for_the_birds

这看起来有点过分,但不知何故,引号的组合可以保持“打印为字面量”。然后,如果我没记错的话,变量只是用引号括起来:“$1”。试试吧,让我知道它对SED的效果如何。

不要忘记所有的快乐发生在壳的限制'和'

所以(ksh)

Var=">New version of \"content' here <"
printf "%s" "${Var}" | sed "s/[&\/\\\\*\\"']/\\&/g' | read -r EscVar

echo "Here is your \"text\" to change" | sed "s/text/${EscVar}/g"

替换子句中只有三个特殊处理的文字字符是/(关闭子句)、\(转义字符、反向引用和&c.)和&(在替换中包含匹配)。因此,你所需要做的就是转义这三个字符:

sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"

例子:

$ export REPLACE="'\"|\\/><&!"
$ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
foo'"|\/><&!bar

警告:不考虑换行。要获得更深入的答案,请参阅这个so问题。(谢谢Ed Morton和Niklas Peter)

请注意,逃避一切是一个坏主意。Sed需要对许多字符进行转义,以获得它们的特殊含义。例如,如果转义替换字符串中的一个数字,它将转换为反向引用。

正如Ben Blank所说,在替换字符串中只有三个字符需要转义(转义本身,正斜杠表示语句结束,&表示replace all):

ESCAPED_REPLACE=$(printf '%s\n' "$REPLACE" | sed -e 's/[\/&]/\\&/g')
# Now you can use ESCAPED_REPLACE in the original sed statement
sed "s/KEYWORD/$ESCAPED_REPLACE/g"

如果你需要转义KEYWORD字符串,下面是你需要的:

sed -e 's/[]\/$*.^[]/\\&/g'

并可用于:

KEYWORD="The Keyword You Need";
ESCAPED_KEYWORD=$(printf '%s\n' "$KEYWORD" | sed -e 's/[]\/$*.^[]/\\&/g');

# Now you can use it inside the original sed statement to replace text
sed "s/$ESCAPED_KEYWORD/$ESCAPED_REPLACE/g"

请记住,如果使用/以外的字符作为分隔符,则需要将上面表达式中的斜杠替换为您正在使用的字符。请参阅PeterJCLaw的评论以获得解释。

编辑:由于以前没有考虑到的一些极端情况,上面的命令已经更改了几次。详细信息请查看编辑历史记录。