我正在尝试替换文件中跨多行的一些文本。有一个开始模式和一个结束模式需要匹配。
<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,}
似乎没有什么效果。我尝试过双引号,更改分隔符,但我在这里运气不佳。我在这里查看了许多示例,但似乎没有一个示例能够同时解决变量替换问题。
这可能对你有用(GNU sed):
sed -i'.bak' -ne '\#'"$BEGIN"'#{p;:a;n;\#'"$END"'#!ba;i\'"$REPLACE" -e '};p' file
使用
-i
选项备份原始文件。使用 -n
选项禁止自动打印图案空间。使用 -e
选项允许 sed 命令占据一行。
正则表达式的正常分隔符是
/
字符,但是 bash 变量可能包含它,因此请使用替代方案(在这种情况下,已选择 #
)。
如果当前行包含
$BEGIN
中的字符串,则打印它,并循环,直到$END
中的字符串为当前行。在 $REPLACE
中插入字符串并打印所有其他行(包括包含 $END
的行)。
如果
$REPLACE
包含多行,除了最后一行之外的每一行都需要以 \
结尾,另一种方法是将替换的内容放在文件中并使用以下解决方案。
sed -i'.bak' -ne '\#'"$BEGIN"'#{p;:a;n;\#'"$END"'#!ba;e cat '"$FILE" -e '};p' file
其中
$FILE
现在包含替换项,但是由于这使用 e
命令(调用 cat
命令),因此需要首先导出 $FILE
变量,例如
cat <<\!>replacementFile.txt
foo
bar
baz
!
export FILE="replacementFile.txt"