转义sedreplace模式的string
在我的bash脚本中,我有一个外部(从用户接收)string,我应该在sed模式中使用。
REPLACE="<funny characters here>" sed "s/KEYWORD/$REPLACE/g"
我怎样才能逃避$REPLACE
string,所以它会被sed
安全地接受为字面replace?
注: KEYWORD
是一个哑巴的子串,没有匹配等,它不是由用户提供。
警告 :这不考虑换行符。 为了得到更深入的答案,请参阅这个SO-问题 。 (谢谢,Ed Morton&Niklas Peter)
请注意,逃避一切是一个坏主意。 Sed需要很多字符才能逃脱以获得其特殊的含义。 例如,如果您在replacestring中转义一个数字,它将变成反向引用。
正如Ben Blank所说,replacestring中只有三个字符需要转义(转义本身,语句结束的正斜杠和全部replace):
sed -e 's/[\/&]/\\&/g'
如果您需要转义KEYWORD
string,以下是您需要的一个:
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合作的。
如果发生这种情况,您正在生成一个随机密码传递给sed
replace模式,那么您select要注意随机string中的哪一组字符。 如果您select通过编码值为base64的密码,那么在base64中只有可能的字符,并且也是sed
replace模式中的特殊字符。 该字符是“/”,可以很容易地从您正在生成的密码中删除:
# 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