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

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

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

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

有帮助吗?

解决方案

警告:这考虑换行。有关更深入的答案,请参阅这个SO问题来可靠地逃避正则表达式元字符。 (谢谢,Ed Morton和Niklas Peter)

请注意,逃避一切都是个坏主意。 Sed需要将许多字符转义为获取其特殊含义。例如,如果您转义替换字符串中的数字,它将转入反向引用。

正如Ben Blank所说,在替换字符串中只需要转义三个字符(自行转义,转发语句结束正斜杠和&amp;替换全部):

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

如果您需要转义 KEYWORD 字符串,则需要以下内容:

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

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

已编辑:由于之前未考虑的某些角落情况,上述命令已多次更改。查看编辑历史记录以获取详细信息。

其他提示

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

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

双引号不是问题。

在replace子句中专门处理的唯一三个文字字符是 / (用于关闭子句), \ (用于转义字符,反向引用和&amp; c) 。)和&amp; (在替换中包含匹配)。因此,您需要做的就是逃避这三个字符:

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的正则表达式,我创建了一个bash函数,可以逃避关键字和替换。

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 | bar | foo 而不是 s / foo / bar /

而且,这是简单的方法:

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

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

事实证明你提出了错误的问题。我也问了一个错误的问题。它错误的原因是第一句话的开头:“在我的 bash 脚本中......”。

我有同样的问题&amp;犯了同样的错误。如果你正在使用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 -v R='//addr:\\file' '{ sub("THIS", R, <*>); print <*> }' <<< "http://file:\_THIS_/path/to/a/file\\is\\\a\\ nightmare"
http://file:\_//addr:\file_/path/to/a/file\\is\\\a\\ nightmare

这是我前一段时间使用的AWK示例。这是一款打印新AWKS的AWK。 AWK和SED相似,可能是一个很好的模板。

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

它看起来过分,但不知何故,引号的组合有助于保持'打印为文字。然后,如果我没记错的话,vaiables只是用这样的引号包围:“$ 1”。试试吧,让我知道它如何与SED一起使用。

我对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扩展并保留制表符或双空格。

其他管道 | sed -e:\ t:\\ t:g'(我喜欢作为标记),它转换了 \ t 中的标签。

不要忘记围绕“shell限制”发生的所有乐趣。和'

所以(在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 替换模式,那么您选择要小心随机字符串中的哪组字符。如果您选择通过将值编码为base64而生成的密码,那么在base64中只有可能的字符,并且在 sed 替换模式中也是一个特殊字符。该字符为“/”,可以轻松地从您生成的密码中删除:

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

如果您只是想在sed命令中替换Variable值,那么只需删除即可 例如:

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

更简单的方法是手工构建字符串并将其用作 sed

的参数
rpstring="s/KEYWORD/$REPLACE/g"
sed -i $rpstring  test.txt
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top