【问题标题】:how to parse a config file for selected output?如何解析选定输出的配置文件?
【发布时间】:2019-07-21 11:06:53
【问题描述】:

我的主目录 (linux) 中有一个文本配置文件。这是格式:

ip nat pool nat_pool1 192.168.10.100 192.168.10.100 netmask /24
!
ip route 0.0.0.0 /0 192.168.15.1
!
slb server websrv1 192.168.10.5
  port 80 tcp
!
slb server websrv2 192.168.10.6
  port 80 tcp
!
slb server websrv3 192.168.10.7
  port 80 tcp
!
slb service-group websrv_80 tcp
  member websrv1 80
  member websrv2 80
  member websrv3 80
!
slb virtual-server websrv1 192.168.15.11
  port 80 tcp
    source-nat pool at_pool1
    service-group websrv_80
!
end

我需要一个脚本(perl?/python?),可以输入如下参数:

脚本名称虚拟服务器名称

然后生成输出,显示与虚拟服务器相关的 source-nat 和服务组详细信息。因此,在下面的示例配置中,如果运行 "script_name websrv1"

脚本将解析 websrv1 虚拟服务器并显示输出以及与之相关的 source-nat 和 slb-service-group 配置信息。该脚本将输出如下内容:

slb virtual-server websrv1 192.168.15.11
  port 80 tcp
    source-nat pool at_pool1
    service-group websrv_80

slb service-group websrv_80 tcp  
  member websrv1 80  
  member websrv2 80  
  member websrv3 80  

ip nat pool nat_pool1 192.168.10.100 192.168.10.100 netmask /24

如果它也在其下方添加了 websrv1、2 和 3 行,那将是一个额外的好处。非常感谢任何帮助。

【问题讨论】:

    标签: python perl parsing


    【解决方案1】:

    这可以通过一个相对简单的awk脚本来完成,修改自this stackoverflow post.

    awk '/websrv1/{flag=1}/!/{flag=0;}flag' config-file.conf 
    

    根据需要将 websrv1 替换为您感兴趣的搜索词,并将 config-file.conf 替换为要搜索的文件。

    【讨论】:

      【解决方案2】:

      由于您自己没有付出任何努力,但感谢您的帮助,这里有一些东西可以帮助您开始使用 perl:

      你知道吗

      if (cond .. cond) {
      }
      

      这可以在这样的while循环中使用:

      while (<>) {
          if (/^slb/ .. /^(!|END)/) {
            ... here you can collect your slb-blocks into a hash
          }
      }
      

      如果您已将数据读入哈希,例如:

      'slb service-group websrv_80 tcp' => "  member websrv1 80\n  member websrv2 80\n  member websrv3 80",
      'slb virtual-server websrv1 192.168.15.11' => "  port 80 tcp\n    source-nat pool at_pool1\n    service-group websrv_80"
      

      我认为迭代散列键并打印出值会很容易。此外,您还可以解析输出以获取要打印的任何其他数据。

      【讨论】:

        【解决方案3】:

        由于您的配置文件是结构化的,您的脚本需要的第一件事就是检测部分。以下是我在 Perl 中的第一次尝试:

        • STDIN读取行
        • 标量上下文中的范围运算符,即作为触发器,用于检测节的开始和结束
        • 在该部分中
          • 解析起始行以检测类型
          • 解析其他行
          • 根据截面类型的生产线
        use strict;
        use warnings;
        
        while (<STDIN>) {
            chomp;
        
            if (/^slb\s+/../^!\s*$/) {
                #print "SECTION: $_\n";
                my($type, $remainder);
        
                # start line
                if      (($type, $remainder) = /^slb\s+(\S+)\s+(.+)/) {
                    print "SECTION ${type} START (${remainder})\n";
        
                # other lines in section
                } elsif (($type, $remainder) = /^\s+(\S+)\s+(.+)/) {
                    print "OTHER ${type} LINE (${remainder})\n";
        
                # end line, i.e. "!"
                } else {
                    #print "END LINE: $_\n";
                }
            }
        }
        exit 0;
        

        使用您的示例进行测试:

        $ perl dummy.pl <dummy.txt
        SECTION server START (websrv1 192.168.10.5)
        OTHER port LINE (80 tcp)
        SECTION server START (websrv2 192.168.10.6)
        OTHER port LINE (80 tcp)
        SECTION server START (websrv3 192.168.10.7)
        OTHER port LINE (80 tcp)
        SECTION service-group START (websrv_80 tcp)
        OTHER member LINE (websrv1 80)
        OTHER member LINE (websrv2 80)
        OTHER member LINE (websrv3 80)
        SECTION virtual-server START (websrv1 192.168.15.11)
        OTHER port LINE (80 tcp)
        OTHER source-nat LINE (pool at_pool1)
        OTHER service-group LINE (websrv_80)
        

        替代方案:因为您的脚本需要将语义含义附加到已解析的内容并在不同类型的“对象”(虚拟、服务器、组...)之间建立联系,您应该研究一下为您的配置文件语法编写一个真正的词法分析器/解析器。最后,这将比手动解析行更乏味。

        【讨论】:

          【解决方案4】:

          这是一个如何开始使用Regexp::Grammars的示例:

          use strict;
          use warnings;
          use Regexp::Grammars;
          
          my $parser = qr{   
                    <nocontext:>
                    <blocks>
                    <rule: blocks> (?: <[block]><.block_separator>)*
                    <rule: block> <[line]>+
                    <token: line> ^(?: $ | (?: (?!(?:end | !))(?: .*?$)))\n?
                    <token: block_separator> ^(?: end | !)\s*\n?
          }mx;
          
          my $fn = 'config.txt';
          open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
          my $text = do { local $/; <$fh> };
          close $fh;
          
          if ($text =~ $parser) {
              for my $block (@{ $/{blocks}{block} }) {
                  print join '', @{ $block->{line} };
                  print "\n", '-' x 40, "\n";
              }
          }
          

          输出

          ip nat pool nat_pool1 192.168.10.100 192.168.10.100 netmask /24
          
          ----------------------------------------
          ip route 0.0.0.0 /0 192.168.15.1
          
          ----------------------------------------
          slb server websrv1 192.168.10.5
            port 80 tcp
          
          ----------------------------------------
          slb server websrv2 192.168.10.6
            port 80 tcp
          
          ----------------------------------------
          slb server websrv3 192.168.10.7
            port 80 tcp
          
          ----------------------------------------
          slb service-group websrv_80 tcp
            member websrv1 80
            member websrv2 80
            member websrv3 80
          
          ----------------------------------------
          slb virtual-server websrv1 192.168.15.11
            port 80 tcp
              source-nat pool at_pool1
              service-group websrv_80
          
          ----------------------------------------
          

          【讨论】:

            猜你喜欢
            • 2011-10-12
            • 2021-06-16
            • 2014-09-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-06-26
            • 2010-11-30
            相关资源
            最近更新 更多