首页 > 解决方案 > 替换变量替换的两个模式匹配之间的多行

问题描述

我正在尝试替换跨越多行的文件中的一些文本。有一个开始模式和一个结束模式要匹配。

<User darthvader>
    home    /deathstar/
    lightsaber    red
</User>

开始模式

<User darthvader>

结束模式

</User>

替换介于两者之间的所有内容。此文件中将有多个不同的用户使用相同的格式。

我需要使用变量,并且需要扩展这些变量。我认为这是它开始对我不起作用的地方。<User我认为和之间的空格也可能存在问题darthvader

举个例子;

BEGIN
    home    /deathstar/
    lightsaber    red
END

如果我使用这个 sed 命令

#!/bin/bash
FILE_TO_EDIT="/file.txt"

sed -e '/BEGIN/{ N; s/BEGIN.*END/MAY THE FORCE BE WITH YOU/ }' ${FILE_TO_EDIT} >${FILE_TO_EDIT}.tmp && mv ${FILE_TO_EDIT}{.tmp,}

这给了我

BEGIN
MAY THE FORCE BE WITH YOU
END

所以我知道我在正确的轨道上。但是一旦我尝试做类似的事情

#!/bin/bash
FILE_TO_EDIT="/file.txt"
USER="darthvader"
BEGIN="<User ${USER}>"
END="</User>"
REPLACE="Booyah!"

sed -e "/${BEGIN}/{ N; s/${BEGIN}.*${END}/${REPLACE}/ }" ${FILE_TO_EDIT} >${FILE_TO_EDIT}.tmp && mv ${FILE_TO_EDIT}{.tmp,}

似乎没有任何效果。我试过双引号,改变分隔符我只是在这里没有任何运气。我在这里查看了许多示例,但似乎没有一个示例同时解决变量替换问题。

标签: sed

解决方案


这可能对您有用(GNU sed):

sed -i'.bak' -ne '\#'"$BEGIN"'#{p;:a;n;\#'"$END"'#!ba;i\'"$REPLACE" -e '};p' file

使用该-i选项备份原始文件。使用该-n选项禁止自动打印图案空间。使用-e选项允许 sed 命令占用一行。

regexp 的常规分隔符是/字符,但是 bash 变量可能包含它,因此请使用替代项(在这种情况下#已选择)。

如果当前行包含 in 的字符串$BEGIN,则打印它,并循环直到 in 的字符串$END是当前行。将字符串插入$REPLACE并打印所有其他行(包括包含 的行$END)。

如果$REPLACE包含多行,除最后一行之外的每一行都需要以 结尾\,另一种方法是将替换的内容放在一个文件中并使用以下解决方案。

sed -i'.bak' -ne '\#'"$BEGIN"'#{p;:a;n;\#'"$END"'#!ba;e cat '"$FILE"' -e '};p' file

where $FILEnow 包含替换,但是由于它使用e命令(调用cat命令),$FILE因此需要首先导出变量,例如

cat <<\!>replacementFile.txt
foo
bar
baz
!

export FILE="replacementFile.txt"

推荐阅读