从匹配的字符串中删除第 N 行(出现多次 - 但仅删除第一次出现)

从匹配的字符串中删除第 N 行(出现多次 - 但仅删除第一次出现)
CPUNAME AGENT_1
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_2
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  TIMEZONE abc
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_3
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


DOMAIN MASTERDM
  *MANAGER AGENT_1
  ISMASTER
END
  1. 首先在上面的文件中,我在模式匹配“TYPE”之后附加了一行“IGNORE”。

    sed -i '/^    TYPE.*/a IGNORE' filename 
    
  2. 我需要删除特定CPU的IGNORE标志,例如AGENT_1 AGENT_3,但是IGNORE的位置并不固定,如上所示。不同街区的第 8、9 和 6 号即将到来。截至目前,我知道我正在编辑文件 IGNORE 标志的 CPU 位于第 8 个位置,因此我使用了一个for循环并删除了 IGNORE。

    for s in `cat $INPUT_FILE | awk '{print $1}'`; do
            echo $s
            sed -i "/$s/!b;n;n;n;n;n;n;n;d" Filename
    done
    
  3. 据我所知,所有块的 NODE 位置始终是固定的,我使用以下命令来替换该行。

    for n in `cat $INPUT_FILE`; do
        CPU=$(echo $n | cut -f1)
        NODE=$(echo $n | cut -f2)
        echo "$CPU"
        echo "$NODE"
        sed -i "/$CPU/!b;n;n;n;c $NODE" filename
    done
    

以上所有工作正常,除了删除特定 CPU 的忽略(如果它不是固定线路)。请提供您宝贵的建议来改进解决方案。

答案1

任务:删除IGNORE指定 CPU 名称的行

如果你想删除该IGNOREAGENT_1AGENT_3你可以使用

awk '$1 == "CPUNAME" && ($2 == "AGENT_1" || $2 == "AGENT_3") { x=1 }
/^END$/ { x=0 }
x && /^ *IGNORE$/ { next }
1' inputfile

您可以根据需要在条件中添加或删除 CPU 名称。

这会将修改后的数据打印到标准输出。一般来说,我不建议就地编辑,因为如果出现任何问题,您可能会丢失数据。如果您确实想用不支持就地编辑的工具替换输入文件,您始终可以使用类似

awk 'some script' inputfile > tempfile && mv tempfile inputfile

解释

  • $1 == "CPUNAME" && ($2 == "AGENT_1" || $2 == "AGENT_3")如果第一个字段是CPUNAME并且第二个字段是指定名称之一,则条件匹配。
  • { x=1 }设置标志x来标记我们要IGNORE在此块中删除的内容
  • /^END$/ { x=0 }如果整行与块末尾的END清除标志匹配。x
  • x && /^ *IGNORE$/仅当设置了IGNORE标志时才匹配带有前导空格的行的条件。x
  • { next }跳过该行的进一步处理,即不打印它。
  • 1是一个true(=每行)条件,没有默认为 的操作print。 (您可以将其写得更详细,如{ print }。)

使用问题中的示例输入

CPUNAME AGENT_1
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_2
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  TIMEZONE abc
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_3
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


DOMAIN MASTERDM
  *MANAGER AGENT_1
  ISMASTER
END

输出是

CPUNAME AGENT_1
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_2
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  TIMEZONE abc
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_3
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
    TYPE MANAGER
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


DOMAIN MASTERDM
  *MANAGER AGENT_1
  ISMASTER
END


反向任务:插入IGNORE

如果真实的输入文件没有IGNORE行,您还可以使用一个脚本,仅将这些行插入到该行后与指定 CPU 名称匹配(或不匹配)的块中TYPE

示例:插入与和IGNORE都不匹配的块AGENT_1AGENT_3

awk '$1 == "CPUNAME" && ($2 != "AGENT_1" && $2 != "AGENT_3") { x=1 }
/^END$/ { x=0 }
1
x && $1 == "TYPE" { print "    IGNORE" }' inputfile

解释:(仅与第一个脚本不同的地方)

  • $1 == "CPUNAME" && ($2 != "AGENT_1" && $2 != "AGENT_3")第一个字段CPUNAME和第二个字段都不是这两个名称。
  • x && $1 == "TYPE"标志x已设置,第一个字段是TYPE
  • { print " IGNORE" }打印IGNORE行(TYPE行后)

AGENT_1使用 CPU ..AGENT_4且无行的示例输入IGNORE

CPUNAME AGENT_1
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_2
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  TIMEZONE abc
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_3
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
    TYPE MANAGER
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_4
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
    TYPE MANAGER
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


DOMAIN MASTERDM
  *MANAGER AGENT_1
  ISMASTER
END

结果输出:

CPUNAME AGENT_1
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_2
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
  TIMEZONE abc
  DOMAIN MASTERDM
  FOR MAESTRO
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_3
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
    TYPE MANAGER
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


CPUNAME AGENT_4
  DESCRIPTION "MANAGER CPU"
  OS UNIX
  NODE xxxxxxxxx.xxx.xxx.cxx TCPADDR 31111
    TYPE MANAGER
    IGNORE
    AUTOLINK ON
    BEHINDFIREWALL OFF
    FULLSTATUS ON
END


DOMAIN MASTERDM
  *MANAGER AGENT_1
  ISMASTER
END

答案2

使用(以前称为 Perl_6)

~$ raku -e 'my @a = slurp.split("\n\n"); .subst("    IGNORE\n").put if .match(/AGENT_1 | AGENT_3/) for @a;'  file

简而言之,上面的代码使用 Raku 编程语言。使用 读取整个文件slurp,并按\n\n连续的换行符拆分为记录,这些记录存储在数组 中@a。然后,如果记录match是所需的任何一个AGENT,则该记录将被删除put,其中“ IGNORE\n”行不被任何内容替换(即被删除)。

https://raku.org

相关内容