正则表达式匹配大括号中的文本并打印整个大括号

正则表达式匹配大括号中的文本并打印整个大括号

我有如下配置文件:

define host{
        host_name xxxxxxxx1748
        use windows-server
        alias Comet
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address XXX.XXX.XXX.XXX
}


define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

我想搜索主机名,如果匹配,输出应如下所示:

示例 - 假设我想搜索yyyyyyyyy991主机。

那么输出必须如下所示:

define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

答案1

尝试这个,

perl -0777 -ne '/([^\n]*{[^}]*(yyyyyyyyy991)[^}]*})/ && print "$1\n"' file

解释:

  • perl -0777运行 perl 并将整个文件作为一行读取。
  • -ne对于每一行 ( n),执行e以下 ( ) 操作。
  • /(pattern)/ && print "$1\n"匹配正则表达式模式并将其添加为第一个匹配组 ( $1),然后打印它。

模式:

  • [^\n]*{ ... }匹配从行首开始的任何内容,包括“{”到下一个“}”
  • ...存在[^}]*(yyyyyyyyy991)[^}]*
    • 匹配任何不是的字符}
    • 必须包括yyyyyyyyy991某处。

答案2

如果您grep支持它,您可以使用该-z选项使其吞噬整个文件:

$ grep -ozE 'define[^}]*host_name yyyyyyyyy991.+?}.' file
define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

使用的选项grep是(来自manGNU 页面grep):

  -z, --null-data
          Treat  input  and output data as sequences of lines, each terminated by a
          zero byte (the ASCII NUL character) instead of a newline.  Like the -Z or
          --null  option,  this  option  can  be used with commands like sort -z to
          process arbitrary file names.
  -o, --only-matching
          Print only the matched (non-empty) parts of a matching  line,  with  each
          such part on a separate output line.
  -E, --extended-regexp
          Interpret PATTERN as an extended regular expression (ERE, see below).

正则表达式查找单词define,后跟 0 个或多个非}字符 ( [^}]*),然后host_name yyyyyyyyy991是所有内容,直到第一个}( ) 加上下一个与换行符匹配的.+?字符(最后一个)。.


然而,就我个人而言,我会使用 Perl 的段落模式来做这样的事情:

$ perl -00 -ne 'print if /yyyyyyyyy991/' file
define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

指示-00perl输入文件作为段落读取,因此每个记录都是一个段落(由 2 个连续\n字符定义)而不是一行。然后,-ne意思是“读取每个输入记录并对其应用给定的脚本-e”。脚本本身只是打印与所需模式匹配的任何记录。

答案3

假设您的配置文件名为 config.dat 并且它有标准格式。这意味着 yyyyyyyyy991 之前只有一行,后面只有五行,那么这个命令将帮助您获得所需的输出:

grep -B 1 -A 5 "yyyyyyyyy991" config.dat

define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

grep男人:

Context control flage:
  -B, --before-context=NUM  print NUM lines of leading context
  -A, --after-context=NUM   print NUM lines of trailing context

如果文件 config.dat 是另一种解决方案不标准,这意味着关键字“yyyyyyyyy991”在每个部分中不遵循相同的模式,然后awk可以按如下方式执行您想要的操作:

 awk -v RS='' '/host_name yyyyyyyyy991/' config.dat

RS= 将输入记录分隔符从换行符更改为空行。如果记录中的任何字段包含 /host_name yyyyyyyyy991/ 则打印该记录。

根据 posix

如果 RS 为空,则记录由由一个或多个空行组成的序列分隔,前导或尾随空行不应导致输入的开头或结尾处出现空记录,并且 a 应始终是字段分隔符,不管FS的值是多少。

输出段落不会被分隔,因为输出分隔符仍然是单个换行符。为了确保输出段落之间有空行,请将输出记录分隔符设置为两个换行符。

答案4

使用sed

sed 'H;/^define host{$/h;/^}/{g;/host_name yyyyyyyyy991\n/p};d' file

一步步:

H                  # append line to hold space
/^define host{$/h  # start of entry: copy to hold space (overwrites previous content)
/^}/{              # end of entry:
        g                            # retrieve whole entry from hold space
        /host_name yyyyyyyyy991\n/p  # if host matched, display the whole entry
}
d                  # no other output

相关内容