使用sed替换包含斜杠和特殊字符的字符串部分

时间:2015-12-31 03:15:12

标签: bash sed

我的配置如下:

{
  "taskdb": "sqlite+taskdb:///taskdb.db",
  "projectdb": "sqlite+projectdb:///projectdb.db",
  "resultdb": "sqlite+resultdb:///resultdb.db",
  "message_queue": "redis://:tFjlvTZ%V4#&YtGl7JEa2l#&@127.0.0.1:6379/0",
}

我想通过shell脚本更改Redis密码。 似乎通常使用sed来完成这项工作,但我发现很难处理。

首先,我尝试匹配redis://:tFjlvTZ%V4#&YtGl7JEa2l#&@

我尝试了以下方法,但他们没有工作:

1. `sed -i 's/^redis:\/\/:.+@$/{&}/g' config.json`
2. `sed -i 's#^redis://:.+@$#{&}#g' config.json`
3. `sed -i 's/redis:\/\/:.+@/{&}/g' config.json`

我真正想要匹配的是tFjlvTZ%V4#&YtGl7JEa2l#&并将其替换为新密码。但我甚至无法匹配该行。

3 个答案:

答案 0 :(得分:2)

试试这个:

sed -i 's#redis://:[^@]*#redis://:NEW_PASSWORD_HERE#g' config.json

如果您不想要.bak文件:

sed -i '' 's#redis://:[^@]*#redis://:NEW_PASSWORD_HERE#g' config.json

我们基本上是在搜索"任何不是@符号的字符"在redis://:之后,用redis://:NEW_PASSWORD_HERE替换整个前导字符串。

现在,如果您只想专门匹配包含message_queue的行,您也可以这样做:

sed -i '/message_queue/s#redis://:[^@]*#redis://:NEW_PASSWORD_HERE#g' config.json

修改

如评论中所述,如果密码中有@(虽然我不认为Redis连接器能够解析它),我们可以使用不同的方法锚定我们的比赛:

sed -i 's#redis://:.*\(@127\.0\.0\.1\)#redis://:NEW_PASSWORD_HERE@127.0.0.1#g' config.json

或者,减少多余的输入:

sed -i 's#\(redis://:\).*\(@127\.0\.0\.1\)#\1NEW_PASSWORD_HERE\2#g' config.json

\1\2代表\(\)之间的两个组。

另一个编辑

您在评论中提到自Regex101 shows that it will以来您希望sed 's/redis:\/\/:.+@/{&}/g' config.json能够正常工作。但是,Regex101使用的是基于Perl的正则表达式引擎,而不是像sed那样使用POSIX风格的正则表达式。此外,没有在"扩展的正则表达式"模式,+运算符无法在sed中工作。这可能会给可移植性带来挑战,因为"扩展的正则表达模式"选项因Linux(-r)和Mac OS X / BSD(-E)而异。不幸的是,我找不到类似于Regex101 for POSIX / ERE正则表达式的正则表达式测试工具。

答案 1 :(得分:2)

乍一看,我看到你的表情有些问题:

首先,您使用^$来界定要匹配的字符串的开头和结尾,但这些运算符意味着您要匹配行的开头和结尾分别。由于你要匹配的字符串位于行的中间,你需要摆脱它们。

第二个是标准的sed不支持+运算符。如果您使用的是GNU sed,则可以为其提供-r选项以获得扩展的正则表达式。或者你可以使用*运算符,这对你来说可能已经足够了。

最后,我不知道您在替换文字中使用{&}了解了什么。难道不仅仅是替换密码吗?

答案 2 :(得分:2)

默认情况下,sed无法将+识别为元字符。如果你有GNU sed,请添加-r以使其识别出来;对于BSD sed,您需要使用-E。 (但是,我们可以推断您使用GNU sed,因为BSD sed需要-i选项的后缀,而您却没有提供后缀。)但是.+符号对于安全而言太贪心了。你真的想要一个或多个'不是 - @'字符。 g修饰符是多余的(但在其他方面无害);您在配置文件中的一行中只有一个URL。那写了:

sed 's/redis:\/\/:[^@]\{1,\}@/{&}/' config.json

这适用于任何版本的sed。你也可以使用:

sed -r 's%redis://:[^@]+@%{&}%' config.json
由于sed

特定于GNU -r。在sed的所有版本中都可以将分隔符从斜杠更改为百分比。

当然,如果您想用新值替换密码组件,并且只要新值不包含任何百分号,您就可以使用:

sed -r 's%(redis://:)[^@]+@%\1new-password@%' config.json

如果您需要在变量中使用密码,请使用双引号而不是单引号:

sed -r "s%(redis://:)[^@]+@%\1${new_password}@%" config.json

另请注意,在您的脚本正常运行之前,您不应该使用-i选项。当然,如果您处理数据文件的副本,那么它不是世界末日,但只有在您确信脚本编辑文件时才添加覆盖通常会更好你希望它的方式。