Linux:匹配一个表达式,然后移除整个相关块

Linux: Match an expression, then remove the entire related block

配置文件看起来像这样(我必须检查数百个):

    define host {
        host_name   db.xxx.yyy
        address     10.5.220.10
        use         yyy-server
        parents     router.xxx.yyy
    }
    define host {
        host_name   drac.vs2.xxx.yyy
        address     10.5.220.48
        use         yyy-drac
        parents     router.xxx.yyy

    }
    define service {
            use             disk-opt-service
            host_name       db.xxx.yyy
    }

我的工作是删除所有包含 db.xxx.yyy 的块 这样结果看起来就像这样(删除了顶部和底部块,因为它们每个都在块中包含 db.xxx.yyy):

    define host {
        host_name   drac.vs2.xxx.yyy
        address     10.5.220.48
        use         yyy-drac
        parents     router.xxx.yyy

    }

sed解决方法:

sed -Ez 's/define (host|service) \{[^}]+db\.xxx\.yyy[^{}]+\}//g' file
  • -z - 将输入视为一组行,每行以零字节(ASCII“NUL”字符)而不是换行符终止

输出:

define host {
    host_name   drac.vs2.xxx.yyy
    address     10.5.220.48
    use         yyy-drac
    parents     router.xxx.yyy

}

A​​wk 一行代码:

awk -v RS='}\n' '/db.xxx/{next} {print [=10=],RS}' file
  • 记录分隔符是 "}\n" 。如果记录包含模式 "db.xxx" 那么 忽略并继续下一条记录否则打印记录包括 RS 即“}”[需要具有多字符 RS 的 GNU-Awk]

输出:

define host {
    host_name   drac.vs2.xxx.yyy
    address     10.5.220.48
    use         yyy-drac
    parents     router.xxx.yyy
}

只要您的输入中有名称到值的映射,最健壮且易于扩展的解决方案是首先创建一个数组(下面的f[])来保存这些名称到值的映射,然后只访问值通过他们的名字,例如:

$ cat tst.awk
/define.*{/ { inBlock=1 }
inBlock {
    f[] = 
    block = block [=10=] ORS
    if ( /}/ ) {
        if ( f["host_name"] != "db.xxx.yyy" ) {
            printf "%s", block
        }
        inBlock = block = ""
        delete f
    }
    next
}
{ print }

这将在任何 UNIX 系统上运行任何 awk,并且由于它是在特定字段上进行字符串比较而不是在整个块上进行正则表达式比较,因此它不会被您要查找的值所混淆错误的字段 and/or 正则表达式元字符 and/or 部分匹配,显然您可以轻松更改它以查找字段组合或您需要测试的任何其他内容。它还一次只将一个块读入内存,因此无论您的输入文件有多大,它都能正常工作。

$ cat file
When chapman billies leave the street,
And drouthy neibors, neibors, meet;
As market days are wearing late,
And folk begin to tak the gate,
While we sit bousing at the nappy,
An' getting fou and unco happy,

    define host {
        host_name   db.xxx.yyy
        address     10.5.220.10
        use         yyy-server
        parents     router.xxx.yyy
    }
    define host {
        host_name   drac.vs2.xxx.yyy
        address     10.5.220.48
        use         yyy-drac
        parents     router.xxx.yyy

    }
    define service {
            use             disk-opt-service
            host_name       db.xxx.yyy
    }

We think na on the lang Scots miles,
The mosses, waters, slaps and stiles,
That lie between us and our hame,
Where sits our sulky, sullen dame,
Gathering her brows like gathering storm,
Nursing her wrath to keep it warm.

 - Tam O'Shanter by Robert Burns

.

$ awk -f tst.awk file
When chapman billies leave the street,
And drouthy neibors, neibors, meet;
As market days are wearing late,
And folk begin to tak the gate,
While we sit bousing at the nappy,
An' getting fou and unco happy,

    define host {
        host_name   drac.vs2.xxx.yyy
        address     10.5.220.48
        use         yyy-drac
        parents     router.xxx.yyy

    }

We think na on the lang Scots miles,
The mosses, waters, slaps and stiles,
That lie between us and our hame,
Where sits our sulky, sullen dame,
Gathering her brows like gathering storm,
Nursing her wrath to keep it warm.

 - Tam O'Shanter by Robert Burns

这可能适合您 (GNU sed):

sed '/^\s*define/{:a;N;/^\s*}/M!ba;/db\.xxx\.yyy/d}' file

匹配以 define 开头的行并向其追加更多行,直到匹配以 } 开头的行。如果这些行包含字符串 db.xxx.yyy 则将其删除。