转义sedreplace模式的string

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

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

我怎样才能逃避$REPLACEstring,所以它会被sed安全地接受为字面replace?

注: KEYWORD是一个哑巴的子串,没有匹配等,它不是由用户提供。

警告 :这不考虑换行符。 为了得到更深入的答案,请参阅这个SO-问题 。 (谢谢,Ed Morton&Niklas Peter)

请注意,逃避一切是一个坏主意。 Sed需要很多字符才能逃脱以获得其特殊的含义。 例如,如果您在replacestring中转义一个数字,它将变成反向引用。

正如Ben Blank所说,replacestring中只有三个字符需要转义(转义本身,语句结束的正斜杠和全部replace):

 sed -e 's/[\/&]/\\&/g' 

如果您需要转义KEYWORDstring,以下是您需要的一个:

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

附录:请记住,如果您使用除/以外的字符作为分隔符,则需要用上述expression式中的斜杠来replace正在使用的字符。 请参阅PeterJCLaw的解释。

为KEYWORD变体修正1:添加了两个字符Peter.O提到,'('和')'。

修复2 KEYWORD变种:再次删除'('和')'。 当我添加它们时,不知道我在想什么。 谢谢,杰西。

sed命令允许您使用其他字符而不是/作为分隔符:

 sed 's#"http://www\.fubar\.com"#URL_FUBAR#g' 

双引号不是问题。

在replace子句中特别对待的三个字面字符是/ (closures子句), \ (用于转义字符,反向引用,&)和& (包括replace中的匹配)。 因此,你所要做的就是逃避这三个angular色:

 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 

基于Pianosaurus的正则expression式,我做了一个bash函数,可以逃避关键字和replace。

 function sedeasy { sed -i "s/$(echo $1 | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo $2 | sed -e 's/[\/&]/\\&/g')/g" $3 } 

以下是你如何使用它:

 sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf 

回应有点晚了…但是有一个更简单的方法来做到这一点。 只要改变分隔符(即分隔字段的字符)。 所以,而不是s/foo/bar/你写s|bar|foo

而且,这是简单的方法来做到这一点:

 sed 's|/\*!50017 DEFINER=`snafu`@`localhost`\*/||g' 

结果输出没有那个讨厌的DEFINER子句。

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

我有同样的问题,犯了同样的错误。 如果使用bash,则不需要使用sed来进行stringreplace(并且使用内置到bash中的replacefunction要简单得多 )。

而不是像,例如:

 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")" 

您可以专门使用bashfunction:

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

使用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 

这里是我刚才使用的一个AWK的例子。 这是一个AWK打印新的AWKS。 AWK和SED是相似的,它可能是一个很好的模板。

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

它看起来过度,但不知何故,报价的组合,以保持“打印为文字”。 然后,如果我没有记错的话,那么这些数字只是用这样的引号括起来:“$ 1”。 试试吧,让我知道它是如何与SED合作的。

如果发生这种情况,您正在生成一个随机密码传递给sedreplace模式,那么您select要注意随机string中的哪一组字符。 如果您select通过编码值为base64的密码,那么在base64中只有可能的字符,并且也是sedreplace模式中的特殊字符。 该字符是“/”,可以很容易地从您正在生成的密码中删除:

 # password 32 characters log, minus any copies of the "/" character. pass=`openssl rand -base64 32 | sed -e 's/\///g'`; 

我对sedeasy函数有了一个改进,它将与特殊字符(如tab)分离。

 function sedeasy_improved { sed -i "s/$( echo "$1" | sed -e 's/\([[\/.*]\|\]\)/\\&/g' | sed -e 's:\t:\\t:g' )/$( echo "$2" | sed -e 's/[\/&]/\\&/g' | sed -e 's:\t:\\t:g' )/g" "$3" } 

那么,有什么不同? $1$2包裹在引号中以避免shell扩展,并保留制表符或双重空格。

额外的pipe道| sed -e 's:\t:\\t:g' | sed -e 's:\t:\\t:g' (我喜欢:作为标记),它转换了\t一个标签。

一个更简单的方法是简单地构buildstring并将其用作sed的参数

 rpstring="s/KEYWORD/$REPLACE/g" sed -i $rpstring test.txt 

只要在REPLACE varible中逃避一切:

 echo $REPLACE | awk '{gsub(".", "\\\\&");print}' 

不要忘记所有与“壳”限制在“和”

所以(在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" 

如果你只是想在sed命令中replaceVariable值,那么就删除Example:

 sed -i 's/dev-/dev-$ENV/g' test to sed -is/dev-/dev-$ENV/g test