在 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

动态意味着内容可以动态生成,而不是在脚本中硬编码。

我尝试了很多,但还没有找到一种干净的方法来完成这个看似很常见的事情。请告诉我如何使用awksedperl 等命令行工具来执行此操作。

【问题讨论】:

在大多数情况下,您可以只使用 printf 和 shell 本身来修改具有动态模式的文件。 【参考方案1】:

使用所有这些实用程序,将原始文件分成 3 部分非常简单:

从头到尾的分隔符(排除)。 从头到尾的分隔符(包括在内)。 从结束分隔符(排除)到结束。

更换中间部分很容易。以awk 为例,假设要更新的文本是在 bash 变量 str 中准备的,并且 awk 变量 startend 包含与开始和结束分隔符行匹配的正则表达式:

# 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 个分隔线之间操作多行(如果不存在则附加,否则替换)的主要内容,如果未能解决你的问题,请参考以下文章

在 EXTJS3 的 ComboBox 中的选项之间添加分隔线

引导程序中两列之间的垂直分隔线

SQL 如果存在则“是”否则“否”在新列中

codeup1010,多行(无穷多)输入含空格

Pandas - 如果不存在分隔符,则使用默认值拆分列

SQL:如果存在则更新,否则插入...但对于具有不同值的多行