【问题标题】:Remove the contents of block only 1st and 3rd occurence仅删除第 1 次和第 3 次出现的块的内容
【发布时间】:2018-06-04 02:07:45
【问题描述】:

下面的 sed 删除所有出现在 {content-start} 和 {content-end} 之间的块,但只想删除第 1 个和第 3 个块,而不是第 2 个块。

sed -ie '/{content-start.*}/,/{content-end}/d' test.txt

test.txt:

{content-start}
abc1
def1
ghi1
{content-end}
{content-start}
abc2
def2
ghi2
{content-end}
{content-start}
abc3
def3
ghi3
{content-end}

【问题讨论】:

  • 有什么理由只是sed
  • 您是否有理由需要使用这种文件格式?为什么不是 json 或 yaml 甚至 ini 文件格式?
  • sed / awk 没问题。我无法更改文件格式。

标签: awk sed


【解决方案1】:

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

sed -n '/{content-start}/{x;s/^/x/;x;:a;N;/{content-end}/!ba;x;/^x\{2\}$/{x;p;x};x}' file

使用 -n 选项复制 seds grep-like-nature。收集开始和结束标记之间的线条。在收集开始时,将标志附加到保留空间以用作计数器。收集了所有需要的行后,仅当保留空间包含所需的数字时才打印。

此解决方案仅打印第二个块,但是如果您只想排除块 1 和块 3,则:

sed '/{content-start}/{x;s/^/x/;x;:a;N;/{content-end}/!ba;x;/^x\{1\}$/{x;d};/^x\{3\}/{x;d};x}' file

此解决方案仅删除块 1 和 3。

【讨论】:

    【解决方案2】:

    sed 用于单个行上的简单替换,即 s/old/new/,仅此而已。对于其他任何你应该使用 awk 的东西:

    $ awk '{rec = rec $0 ORS} /{content-end}/{if (++cnt == 2) printf "%s", rec; rec=""}' file
    {content-start}
    abc2
    def2
    ghi2
    {content-end}
    

    或者如果你想要对单独的行做任何事情,那么将记录的每一行保存在一个数组中,而不是将整个记录保存为一个字符串:

    { rec[++numLines] = $0 }
    /{content-end}/ {
        if ( ++cnt == 2 ) {
            for (lineNr=1; lineNr<=numLines; lineNr++) {
                print rec[lineNr]
            }
        }
        delete rec
        numLines = 0
    }
    

    以上内容适用于任何 UNIX 系统上的任何 shell 中的任何 awk,并且如果/当您的需求发生变化时可以轻松增强。

    【讨论】:

      猜你喜欢
      • 2017-12-14
      • 2022-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-25
      • 2016-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多