如果一行匹配条件,则 sed 替换与模式范围匹配的行

Posted

技术标签:

【中文标题】如果一行匹配条件,则 sed 替换与模式范围匹配的行【英文标题】:sed to replace lines matched by a pattern range if one line match a condition 【发布时间】:2021-03-15 23:18:27 【问题描述】:

我需要删除以下示例文件格式的记录:

record 
    record 
        my_id_1
        my_name_1
    
    
    record 
        my_id_2
        my_name_2
    
    
    record 
        my_id_3
        my_name_3
    

在这种情况下,我们需要使用唯一值 my_idmy_id_2 删除所有记录数据,预期结果应该是:

record 
    record 
        my_id_1
        my_name_1
    
    
    record 
        my_id_3
        my_name_3
    

注意:该文件不是一个标准的谈论空格,换行等。但核心逻辑可能是删除单词record[包括相同单词]之间的所有内容,仅与my_id_*字符串相关在括号中。

到目前为止,我所能做的就是写:

sed -n '/record/:a;N;//!ba; /my_id_2/p' file.conf

事实上,它找到了我需要的东西,但我无法删除它我只打印我想要清除的行。

sed 是我的主要选择,但 python regex 也可以,因此我可以将其传递给 ansible。

##########################

这也是我的 Python 尝试

##########################

工具:https://pythex.org/

使用 python 这是我得到的最接近的:

第一次尝试: (?=my_id_2)([^]+)(?=\)

有匹配结果:

    `my_id_2 my_name_2`

然后稍作修改: (?=record )([^]+)(?=\)

有匹配结果:

Match 1

    `1. record  record  my_id_1 my_name_1`

Match 2

    `1. record  my_id_2 my_name_2`

Match 3

`1. record  my_id_3 my_name_3`

谢谢。

【问题讨论】:

使用 python 这是我得到的最接近的:第一次尝试:(?=my_id_2)([^]+)(?=\) 匹配结果:my_id_2 my_name_2 然后修改了一下:(?=record )([^]+)(?=\) 匹配结果:Match 11. record record my_id_1 my_name_1@987654346 @1. record my_id_2 my_name_2Match 31. record my_id_3 my_name_3 【参考方案1】:

你可以试试:

$ sed -i.bak '/record/:a;N;//!ba; /my_id_2/d' file.conf
$ cat file.conf
record 
    record 
        my_id_1
        my_name_1
    
    
    
    record 
        my_id_3
        my_name_3
    

以上内容就地修改文件并创建文件的备份,命名为file.conf.bak。如果您不需要原始文件的备份,您可以从-i.bak 中删除.bak

【讨论】:

【参考方案2】:

相信这可以满足您的要求,但它会在前面添加一个空行。它只是将它们作为段落括起来,然后删除具有该记录名称的段落。

sed '/./H;$!d ;x; /my_id_2/d' file.conf

您可能认为可以在 sed 语句后附加一个额外的 ; 1d 来删除它。

sed '/./H;$!d ;x; /my_id_2/d ; 1d' file.conf

但是,这没有任何效果,并且第 1 行仍然是空白的。您可以通过将其传递给后续的sed 命令来克服这个问题,但这似乎很不稳定。也许其他人知道原因。

sed '/./H;$!d ;x; /my_id_2/d' file.conf | sed '1d'

https://www.gnu.org/software/sed/manual/sed.html

【讨论】:

【参考方案3】:

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

sed -E '/record \/:a;N;/\/!ba;/my_id_2/!b;s/(record \.*)\1.*/\1/;t;d' file

使用您的原始方法,但使用贪婪进行额外测试,如果成功,则保留匹配字符串的前面。如果没有这样的匹配,恢复并像以前一样删除整个匹配的字符串。

注意这可能会引入一些不需要的填充,将其删除作为练习留给读者;-)

【讨论】:

以上是关于如果一行匹配条件,则 sed 替换与模式范围匹配的行的主要内容,如果未能解决你的问题,请参考以下文章

Linux三剑客(sed)-编辑匹配到的文本

用 sed 找到匹配时替换整行

shell-sed中的编辑命令详解(中)

sed原理的一些感悟

使用sed替换具有匹配模式的行

当一行与模式匹配时,我可以在sed中执行两个命令吗?