简体   繁体   English

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

[英]Using sed to Replace Portion of String Containing Slashes and Special Characters

I have a config like: 我有一个像这样的配置:

{
  "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",
}

I want to change the Redis password via a shell script. 我想通过外壳脚本更改Redis密码。 Seems it usually using sed to do such work, but I find something hard to cope with. 似乎通常使用sed来完成此类工作,但是我发现有些事情很难解决。

First, I try to match redis://:tFjlvTZ%V4#&YtGl7JEa2l#&@ 首先,我尝试匹配redis://:tFjlvTZ%V4#&YtGl7JEa2l#&@

I have tried the following, but they don't work: 我尝试了以下方法,但是它们不起作用:

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

What I really want to match is tFjlvTZ%V4#&YtGl7JEa2l#& and replace it with a new password. 我真正想要匹配的是tFjlvTZ%V4#&YtGl7JEa2l#&并将其替换为新密码。 But I even can't match the row. 但我什至无法匹配该行。

Try this: 尝试这个:

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

If you don't want a .bak file: 如果您不想要.bak文件:

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

We're basically searching for "any character that isn't an @ sign" after redis://: , and replacing this whole leading string with redis://:NEW_PASSWORD_HERE . 我们基本上是在redis://:之后搜索“不是@符号的任何字符”,然后用redis://:NEW_PASSWORD_HERE替换整个前导字符串。

Now, if you wanted to specifically match only a line that contained message_queue , you could do something like this as well: 现在,如果您只想专门匹配包含message_queue的行,则可以执行以下操作:

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

Edit 编辑

As mentioned in the comments, if there's an @ in the password (although I don't think the Redis connector would be able to parse it), we can use a different method of anchoring our match: 如评论中所述,如果密码中有一个@ (尽管我认为Redis连接器无法解析它),我们可以使用另一种锚定匹配的方法:

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

Or, with less redundant typing: 或者,使用较少的冗余键入:

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

\\1 and \\2 represent the two groups enclosed between \\( and \\) . \\1\\2代表\\(\\)之间的两组。

Another Edit 另一个编辑

You mentioned in the comments that you expected sed 's/redis:\\/\\/:.+@/{&}/g' config.json to work since Regex101 shows that it will . 您在注释中提到,您希望sed 's/redis:\\/\\/:.+@/{&}/g' config.json /:。+ sed 's/redis:\\/\\/:.+@/{&}/g' config.json g'config.json正常工作,因为Regex101显示它可以 However, Regex101 is using Perl-based regular expression engines, rather than POSIX-style regular expressions like sed uses. 但是,Regex101使用的是基于Perl的正则表达式引擎,而不是sed用法之类的POSIX风格的正则表达式。 Additionally, without operating in "extended regex" mode, the + operator won't work in sed . 此外,如果不以“扩展的正则表达式”模式进行操作,则+运算符将无法在sed工作。 This can present a challenge for portability, as the "extended regex mode" option differs on Linux ( -r ) and Mac OS X / BSD ( -E ). 由于“扩展的regex模式”选项在Linux( -r )和Mac OS X / BSD( -E )上有所不同,因此这对可移植性提出了挑战。 Unfortunately, I cannot find a regex testing tool similar to Regex101 for POSIX/ERE regular expressions. 不幸的是,我找不到用于POSIX / ERE正则表达式的类似于Regex101的正则表达式测试工具。

On first glance I see a few problems with your expression: 乍一看,我发现您的表情存在一些问题:

The first is that you are using ^ and $ to delimit the beginning and end of the string you want to match but those operators mean that you want to match the beginning and end of a line respectively. 首先是您使用^$分隔要匹配的字符串的开头和结尾,但是这些运算符意味着您要分别匹配一行的开头和结尾。 Since your string to match is in the middle of the line you need to get rid of them. 由于要匹配的字符串位于行的中间,因此您需要删除它们。

The second is that standard sed doesn't support the + operator. 第二个问题是标准sed不支持+运算符。 If you are using GNU sed you can give it the -r option to get extended regex notation. 如果使用的是GNU sed ,则可以给它-r选项以获取扩展的正则表达式表示法。 Or you can just use the * operator which will probably be good enough for you here. 或者,您可以只使用*运算符,这对您来说可能已经足够了。

Lastly, I don't know what you're going for with the {&} in the replacement text. 最后,我不知道替换文字中的{&}是什么意思。 Shouldn't that just be the replacement password? 那不应该只是替换密码吗?

By default, sed does not recognize + as a metacharacter. 默认情况下, sed不会将+识别为元字符。 If you have GNU sed , add -r to make it recognize it; 如果您具有GNU sed ,请添加-r使其识别它;否则,请添加-r with BSD sed , you'd use -E instead. 对于BSD sed ,您应该使用-E (However, we can infer that you're using GNU sed since BSD sed requires a suffix for the -i option and you're not providing one.) But the .+ notation is too greedy for safety. (但是,我们可以推断出您正在使用GNU sed因为BSD sed需要-i选项的后缀,而您没有提供后缀。)但是.+表示法过于安全。 You really want one or more 'not- @ ' characters. 您确实想要一个或多个'not- @ '字符。 The g modifier is superfluous (but otherwise harmless); g修饰符是多余的(但无害); you've only ever got one URL on a line in the config file. 您在配置文件中的一行上只有一个URL。 That's written: 上面写着:

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

That should work with any version of sed . 那应该适用于任何版本的sed You could also use: 您还可以使用:

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

which is specific to GNU sed because of the -r . 由于-r ,它特定于GNU sed Changing the delimiter from slash to percent is doable in all versions of sed . 在所有版本的sed中都可以将定界符从斜杠更改为百分比。

Of course, if you want to replace the password component with a new value, and as long as the new value does not contain any percent symbols, you can use: 当然,如果要用新值替换密码组件,并且只要新值不包含任何百分比符号,就可以使用:

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

If you need to work with the password in a variable, use double quotes instead of single quotes: 如果需要在变量中使用密码,请使用双引号而不是单引号:

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

Also note that you really shouldn't use the -i option until you've got your script working. 还要注意,在脚本正常运行之前,您实际上不应该使用-i选项。 Granted, if you work on a copy of the data file it isn't the end of the world, but it's usually better to add the overwriting only when you're confident that the script edits the file the way you want it to. 当然,如果您正在处理数据文件的副本,这还不是世界末日,但是通常只有在确信脚本可以按照所需方式编辑文件时才添加覆盖,这样通常会更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM