Использование regex для извлечения имен хостов из файла Nagios cfg

У меня есть файл конфигурации из Nagios, который я успешно разбираю, чтобы извлечь все host_names. Затем я могу использовать эту информацию для сравнения с нашим списком серверов, чтобы узнать, есть ли что-то, что я не контролирую. Есть и другие способы сделать это, но это дает мне повод для работы над моей Powershell и Regex. Соответствующая выборка из моей конфигурации:

<pre class="prettyprint linenums">define host{ use windows-server ; Inherit default values from a template host_name server1 ; The name we're giving to this host alias server1 ; A longer name associated with the host address 10.10.10.19 ; IP address of the host } define host{ use windows-server ; Inherit default values from a template host_name server2 ; The name we're giving to this host alias server2 ; A longer name associated with the host address 10.10.13.62 ; IP address of the host } define host{ use windows-server ; Inherit default values from a template host_name server3 ; The name we're giving to this host alias server3 ; A longer name associated with the host address 10.10.10.21 ; IP address of the host } define service{ use generic-service hostgroup_name windows-servers service_description CPU Usage check_command check_nrpe!alias_cpu } define service{ use generic-service host_name server1 service_description Memory check_command check_nrpe!alias_mem } </pre>

У меня есть следующие аргументы powershell и регулярные выражения

$text = [IO.File]::ReadAllText("windows.cfg")
 $text | Select-String '(?smi)(?<=host\{).*?(?=\})' -AllMatches |
 Foreach {$_.Matches} |
 ForEach-Object {$_.Value} |
 Select-String '(?smi)(?<=host_name\s+)\w+' -AllMatches |
 Foreach {$_.Matches} |
 ForEach-Object {$_.Value}

Я сопоставляю содержимое между host {и}, которое гарантирует, что я не получаю дополнительные узлы из определений служб и хостов. Для каждого соответствия для этого я ищу целое слово, которое существует после статического имени хоста и некоторых пробелов.

Он работает, я просто хочу знать, есть ли более эффективный или альтернативный подход регулярного выражения. Я попытался сделать все это одним запросом, но я мог бы заставить его работать, поэтому он был вложен, как вы можете видеть в коде. Также я должен понять

2 ответа

Я бы сделал это так:

$text | Select-String 'host{[\s\S]*?}' -AllMatches | % {
 $_.Matches.Groups.Value
} | Select-String 'host_name\s*(\S+)' | % {
 $_.Matches.Groups[1].Value
}

Возможно, есть способ сделать это с помощью одного регулярного выражения (не уверен в этом), но выше, вероятно, легче понять и поддерживать.


Я обычно подхожу к такой проблеме, как это:

(@'
define host{
 use windows-server ; Inherit default values from a template
 host_name server1 ; The name we're giving to this host
 alias server1 ; A longer name associated with the host
 address 10.10.10.19 ; IP address of the host
 }

define host{
 use windows-server ; Inherit default values from a template
 host_name server2 ; The name we're giving to this host
 alias server2 ; A longer name associated with the host
 address 10.10.13.62 ; IP address of the host
 }

define host{
 use windows-server ; Inherit default values from a template
 host_name server3 ; The name we're giving to this host
 alias server3 ; A longer name associated with the host
 address 10.10.10.21 ; IP address of the host
 }

define service{ 
 use generic-service 
 hostgroup_name windows-servers 
 service_description CPU Usage 
 check_command check_nrpe!alias_cpu 
 }

define service{ 
 use generic-service 
 host_name server1 
 service_description Memory 
 check_command check_nrpe!alias_mem 
 }
'@).split("'n") |
foreach {$_.trim()} | set-content windows.cfg

get-content windows.cfg -ReadCount 1000 |
 foreach {$_ -match '^\s*host_name' -replace '^\s*host_name\s+(\S+).+','$1'}

server1
server2
server3
server1

Использование Get-Content с -ReadCount позволяет работать с файловыми данными в контролируемых кусках, поэтому у вас нет проблем с памятью, если вы бросаете в него большой файл. Поскольку он передает массивы строк вниз по конвейеру, -match и replace работают как операторы массива, делая весь массив сразу, -match фильтрует записи host_name, а затем -replace извлекает значение из строка.

licensed under cc by-sa 3.0 with attribution.