0

我正在将一些旧的 Nagios 配置数据从 Nagios Core 移植到 Nagios XI。这项工作的一部分意味着我需要提取一些对象定义并将它们放入由主机名命名的单个文件中(示例如下)。我可以看到很多方法来做到这一点,可能是通过编写脚本(Perl/Python/PHP - Nagios XI 脚本似乎都是用 PHP 完成的)。但是我想知道是否有更简单的方法可以做到这一点,也许在命令行上使用awk或类似?令我震惊的是,awk 可以很容易地提取两个定界模式之间的文本行(例如/define host \{//\}/),但我需要将输出分成由 host_name 字段的内容命名的单个文件。

最好的方法是什么?我最好写一个脚本,还是有一个简洁的 awk 命令(或类似命令)可以从 Nagios XI 机器上的 bash shell 运行?

示例整体文件:

define host {
    host_name   testhost1
    use             hosttemplate1
    address                 10.0.0.1
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost1
    icon_image      redhat_icon.png
}
define service {
    use     servtemplate1
    host_name   testhost1
    service_groups  +All
    service_description  A Test Service
}
define host {
    host_name   testhost2
    use             hosttemplate2
    address                 10.0.0.2
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost2
    icon_image      redhat_icon.png
}

期望的输出:

# cat testhost1.cfg
define host {
    host_name   testhost1
    use             hosttemplate1
    address                 10.0.0.1
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost1
    icon_image      redhat_icon.png
}
# cat testhost2.cfg
define host {
    host_name   testhost2
    use             hosttemplate2
    address                 10.0.0.2
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost2
    icon_image      redhat_icon.png
 }

例如,现在我可以运行这样的命令,该命令似乎相当广泛地用于行提取:

# gawk ' /define host / {flag=1;next} /}/{flag=0} flag { print }' example.cfg

这切断了define hostand}但这是一个相对简单的修复 - 但是它将数据作为 shell 中的一个流输出。

我可以实现一些聪明的技巧来完成所有这些工作,包括从外壳上的一个衬里拆分成单独的配置文件,还是我应该编写一个脚本?

4

2 回答 2

2

使用 awk:

单线

awk '/^define host/{f=1;str=$0;next}/host_name/{h=$NF".cfg"}f{str=str ORS $0}f && /^\}/{print "#"h>h; print str>h; f=""; close(h)}' file

解释

awk '
      /^define host/{                # look for line start with define host
                      f=1            # set variable f to 1
                      str=$0         # set variable str = current line/row/record 
                      next           # go to next line
      } 
      /host_name/{                   # look for line with hostname
                     h=$NF".cfg"     # set variable h with last field value plus ".cfg"
      }
      f{                             # if f was true or 1 then
                     str=str ORS $0  # concatenate variable str with current record 
      }
      f && /^\}/{                    # if f is true and line starts with } then
                     print "#"h > h  # write # hostname to file
                     print str > h   # write the content of variable str to file
                     f=""            # nullify variable
                     close(h)        # close file 
      }
    ' file

试验结果

输入:

$ cat file 
define host {
    host_name   testhost1
    use             hosttemplate1
    address                 10.0.0.1
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost1
    icon_image      redhat_icon.png
}
define service {
    use     servtemplate1
    host_name   testhost1
    service_groups  +All
    service_description  A Test Service
}
define host {
    host_name   testhost2
    use             hosttemplate2
    address                 10.0.0.2
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost2
    icon_image      redhat_icon.png
}

执行:

$ awk '/^define host/{f=1;str=$0;next}/host_name/{h=$NF".cfg"}f{str=str ORS $0}f && /^\}/{print "#"h>h; print str>h; f=""; close(h)}' file

生成的文件:

$ cat *.cfg
#testhost1.cfg
define host {
    host_name   testhost1
    use             hosttemplate1
    address                 10.0.0.1
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost1
    icon_image      redhat_icon.png
}
#testhost2.cfg
define host {
    host_name   testhost2
    use             hosttemplate2
    address                 10.0.0.2
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost2
    icon_image      redhat_icon.png
}

在 PHP 中

$ cat test.php
<?php
preg_match_all('~define host\s+?{[^}]*}~', file_get_contents('file'), $match);
foreach($match[0] as $config)
{
    if(preg_match('~host_name\s+([^\s]*)~', $config, $host))
    {
        $file = $host[1].".cfg";
        file_put_contents($file, '#'.$file.PHP_EOL.$config.PHP_EOL);
    }
}
?>

$ php test.php 
$ ls *.cfg
testhost1.cfg  testhost2.cfg
于 2017-09-13T12:16:17.397 回答
0

热烈欢迎来到 Stack Overflow 网站,我希望你会喜欢在这里学习和分享知识,你能否尝试关注并让我知道这是否对你有帮助。

awk '/^}$/ && flag{print > file;flag="";close(file);next} /define host/{flag=1;val=$0;next} flag && /host_name/{file=$2".cfg";print val ORS $0 > file;next} flag{print > file}'   Input_file

编辑:现在也添加非单线形式的解决方案。

awk '
/^}$/ && flag{             ##Looking for a line which starts from } and ends with same only + checking if variable flag is NOT null.
   print > file;           ##printing the current line to variable file(which will be having values like testhost1, testhost2.cfg etc etc
   flag="";                ##Nullifying the variable flag here.
   close(file)             ##Closing the file because in case of Input_file is huge so in backend these files(testconfig1 etc etc) could be opened and which may cause issues in case they all are opened, so it is good practice to close them.
   next                    ##Using next keyword of awk will skip all the further statements for the current line.
}
/define host/{             ##Searching for a line which has string define_host in it.
   flag=1;                 ##Making variable flag value to TRUE now, to keep track that we have seen string define_host in Input_file.
   val=$0;                 ##Storing this current line to a variable named val now.
   next                    ##Using next keyword will skip all further statements for the current line.
}
flag && /host_name/{       ##Checking if flag is TRUE and current line has string host_name in it then do following.
   file=$2".cfg";          ##Creating a variable named file who has value of 2nd field and string .cfg, this is actually the file names where we will save the contents
   print val ORS $0 > file;##printing variable named val then output record separator and current line and redirecting them to variable file which will make sure it should be saved in file named testhost etc etc .cfg.
   next                    ##As mentioned before too, next will skip all further statements.
}
flag{                      ##Checking if variable flag is TRUE or NOT NULL here.
   print > file            ##Printing the current line into the file then.
}
'  Input_file              ##Mentioning the Input_file here.
于 2017-09-13T12:07:02.517 回答