使用 bash(正则表达式,sed)删除模式之间的分隔代码块

Removing delimited block of code between patterns using bash (regex, sed)

我有一个包含 visibility 声明的文件,跨越一行或多行,我想删除 如果它们在 test 块中.

即input.txt:

test(
    srcs = [
        "test1",
    ],
    visibility = [
        "common",
    ],
    deps = [ "deps" ],
)

test(
    srcs = [
        "test2",
    ],
    visibility = [ "common" ],
)

即输出:

test(
    srcs = [
        "test1",
    ],
    deps = [ "deps" ],
)

test(
    srcs = [
        "test2",
    ],
)

可见性线可能在其他块内,即 etc(...),在这种情况下不应删除它们。即:

etc(
    src = [
        "etc",
    ],
    # should not be removed because it's not inside a test(...) block
    visibility = [
        "common",
    ],
)

这是我尝试过的方法,但是,这只匹配跨越单行的 visibility 个块:

#!/bin/bash
#remove_lines.sh
remove_visibility_lines () {
    start_pattern="test"
    end_pattern=")"

    pattern_to_remove="visibility = \[.*\],"

    sed "/${start_pattern}/,/${end_pattern}/{/${pattern_to_remove}/d}" ""
}

remove_visibility_lines 

$ ./remove_lines.sh input.txt

我已经尝试了几种方法来消除跨越多个块的可见性,即 (.*?)(\_.*),但我似乎无法让它工作。 请帮忙?

问题类似于: Using sed to delete all lines between two matching patterns ,但是,在我的例子中,我有嵌套在模式中的模式。即:您只查看 test(...) 块内部,并且仅在这些块内部删除 visibility = [...], 块。

使用 awk,假设没有嵌套 () 个字符:

awk '/^test\(/{f=1} [=10=]==")"{f=0}
     f && /visibility = \[/{v=1} !v; /],/{v=0}' ip.txt
  • /^test\(/{f=1} 如果一行以 test(
  • 开头,则设置标志 f
  • [=17=]==")"{f=0} 清除标记 f 如果一行仅包含 )
  • f && /visibility = \[/{v=1} 设置标志 v 如果 f 也被设置并且一行包含 visibility = [
  • !v; 仅在未设置标志 v 时打印输入行
  • /],/{v=0} 清除标记 v 如果行包含 ],

要传递开始和结束字符串:

$ cat script.awk
index([=11=], start) == 1 { f = 1 }
[=11=] == end { f = 0 }
f && /visibility = \[/ { v = 1 }
! v { print }
/],/ { v = 0 }

$ awk -v start='test(' -v end=')' -f script.awk ip.txt