让我们假设以下 XML 文件:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...
我需要替换第一个 </addresses>
下面是第一个<addresses xmlns="namespace">
通过 </namespace:addresses>
这样文件就变成了:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</namespace:addresses>
some other text
<addresses>
<something else/>
</addresses>
...
我知道 this similar thread ,但以下解决方案均未改变任何内容:
sed -e '/<addresses xmlns="namespace">/!b' -e ':a' -e "s/<\/namespace:addresses>/<\/addresses>/;t trail" -e 'n;ba' -e ':trail' -e 'n;btrail' file.xml
sed -e "/<addresses xmlns=\"namespace\">/,/./ s/<\/namespace:addresses>/<\/addresses>/" file.xml
sed -e "/<addresses xmlns=\"namespace\">/,/<\/namespace:addresses>/ s/<\/namespace:addresses>/<\/addresses>/" file.xml
例如:
sed -e "/<addresses xmlns=\"namespace\">/,/./ s/<\/namespace:addresses>/<\/addresses>/" file.xml
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...
也许这个问题与我正在使用的 sed 有关:impish/21.10 上的 4.7-1ubuntu1 甚至 4.8-1。
有什么建议吗? 我愿意使用任何其他工具 (perl/awk),越简单越好。
最佳答案
perl
更容易比sed
:
perl -0777 -i -pe 's~<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/\1>)[^<]*)*\K</\1>~</namespace:$1>~' file
参见 online demo . 详细信息:
-
<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/\1>)[^<]*)*\K</\1>
- 正则表达式模式匹配-
<
- 一个<
字符 -
(addresses)
- 第 1 组($1
):addresses
-
\s+
- 一个或多个空格 -
xmlns="namespace">
- 一个固定的字符串 -
[^<]*(?:<(?!/\1>)[^<]*)*
- 比(?s:.)*?
更快的替代方案- 基本上,匹配不超过</addresses>
的任何文本字符串 -
\K
- 匹配重置运算符,它会忽略当前匹配内存缓冲区中到目前为止匹配的所有文本 -
</\1>
-(这是最终消耗的并将被替换的):</
+ 第 1 组值(以免重复addresses
) +>
-
-
</namespace:$1>
- 替换为</namespace:
+ 第 1 组值 +>
.
它取代了第一次出现,因为 -0777
将文件变成一个多行文本,没有 g
旗帜。
注意 \1
之间的区别模式内部的反向引用语法和 $1
perl
中替换模式中的替换反向引用命令。
参见 online demo :
s=' some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...'
perl -0777 -pe 's~<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/\1>)[^<]*)*\K</\1>~</namespace:$1>~' <<< "$s"
输出:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</namespace:addresses>
some other text
<addresses>
<something else/>
</addresses>
...
关于sed - 在第一个匹配行之后替换第一个出现的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71738141/