在 2 个分隔线之间操作多行(如果不存在则附加,否则替换)
Posted
技术标签:
【中文标题】在 2 个分隔线之间操作多行(如果不存在则附加,否则替换)【英文标题】:Manipulate multiple lines between 2 delimiter lines (append if not exist else replace) 【发布时间】:2021-12-16 21:46:45 【问题描述】:在 linux 中,我看到很多程序在我的 rc 文件中添加了它们自己的开始和结束分隔符模式之间的内容。例如,使用 conda:
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/home/tidu/miniconda3/bin/conda' 'shell.zsh' 'hook' 2>/dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/home/tidu/miniconda3/etc/profile.d/conda.sh" ]; then
. "/home/tidu/miniconda3/etc/profile.d/conda.sh"
else
export PATH="/home/tidu/miniconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<
我想对我的一些配置做同样的事情。
# dynamic start pattern
dynamic
body
# dynamic end pattern
动态意味着内容可以动态生成,而不是在脚本中硬编码。
我尝试了很多,但还没有找到一种干净的方法来完成这个看似很常见的事情。请告诉我如何使用awk
、sed
或perl
等命令行工具来执行此操作。
【问题讨论】:
在大多数情况下,您可以只使用printf
和 shell 本身来修改具有动态模式的文件。
【参考方案1】:
使用所有这些实用程序,将原始文件分成 3 部分非常简单:
从头到尾的分隔符(排除)。 从头到尾的分隔符(包括在内)。 从结束分隔符(排除)到结束。更换中间部分很容易。以awk
为例,假设要更新的文本是在 bash 变量 str
中准备的,并且 awk 变量 start
和 end
包含与开始和结束分隔符行匹配的正则表达式:
# foo.awk
$0 ~ start
if(n != 0)
n = 3
exit
n = 1
n == 0 || n == 2
print
$0 ~ end
if(n != 1)
n = 3
exit
print str
n = 2
n == 1
next
END
if(n != 0 && n != 2)
print "error"
exit 1
else if(n == 0)
print str
$ start='# dynamic start pattern'
$ end='# dynamic end pattern'
$ str="\
$start
dynamic
body
$end"
$ awk -v str="$str" -v start="^$start\$" -v end="^$end\$" -f foo.awk foo.rc > new.rc
最复杂的部分是检测错误(以相反的顺序开始和结束,一个开始但没有结束,一个结束但没有开始,不止一个开始或结束......)n
awk 变量用于保持当前状态的跟踪:开始前(n=0
),结束后(n=2
),中间(n=1
)或错误(n=3
)。如果出现错误awk
以状态1退出。否则,如果以状态0退出,则可以将旧的rc文件替换为新的。
【讨论】:
以上是关于在 2 个分隔线之间操作多行(如果不存在则附加,否则替换)的主要内容,如果未能解决你的问题,请参考以下文章