
Мне нужно регулярное выражение для сбора записей регистрации хоста DHCP
Мне нужно проанализироватьdhcpd.confфайл, для всех резервирований хостов, и если возможно, захватить их в файл или массив Bash. Так что если резервирование хостов определено следующим образом,
host Service-Ethernet {
hardware ethernet 11:11:11:11:11:11;
fixed-address 192.168.0.3;
option host-name "service";
}
host Service-Wifi {
hardware ethernet 22:22:22:22:22:22;
fixed-address 192.168.0.4;
}
host Test {
hardware ethernet 33:33:33:33:33:33;
fixed-address 192.168.0.5
option host-name "test";
}
Вывод в файл или массив Bash...
11:11:11:11:11:11, 192.168.0.3, service
22:22:22:22:22:22. 192.168.0.4,
, 192.168.0.5, test
Если один из трех параметров отсутствует, оставьте его пустым.
Даже если выражение должно быть применено построчно, это все еще приемлемо. Я могу обернуть выражение через скрипт Bash, который читает файл конфигурации построчно, конечно.
решение1
parse_dhcp.awk
С как
#!/usr/bin/env awk -f
function output() {
printf "%s, %s, %s\n", hw, fa, opt
}
$1 == "host" {
if (NR > 1) output()
hw = fa = opt = ""
next
}
{sub(/;$/, "")}
$1 == "hardware" {hw = $NF}
$1 == "fixed-address" {fa = $NF}
$1 == "option" {opt = $NF; gsub(/"/, "", opt)}
END {output()}
затем
awk -f parse_dhcp.awk dhcp.conf
Что еще более неясно, этот файл имеет допустимый синтаксис Tcl, поэтому нам просто нужно написать DSL, чтобы мы могли оценить файл как скрипт Tcl:
#!/usr/bin/env tclsh
proc host {name data} {
global vars
array set vars {hardware "" fixed-address "" option ""}
eval $data
puts "$vars(hardware), $vars(fixed-address), $vars(option)"
}
proc unknown {cmd args} {
global vars
set vars($cmd) [lindex $args end]
}
set file [lindex $argv 0]
source $file
и
tclsh parse_dhcp.tcl dhcp.conf
решение2
Следующий однострочный код Perl, кажется, выводит почти то, что вам нужно:
perl -ane 'print $F[-1] =~ s/[";]//gr unless /[{}]/; print /^$/ ? "\n" : " "'
но я боюсь, что входные данные могут содержать разделы, которые вы хотите полностью пропустить, поэтому необходимо больше настроек:
perl -ane 'if (/host/ .. /}/) {
print $F[-1] =~ s/[";]//gr unless /[{}]/;
print /}/ ? "\n" : " "
}'
что значит
- если мы находимся между строками, содержащими
host
и}
, мы обрабатываем входные данные, в противном случае мы их пропускаем. - если текущая строка не содержит фигурных скобок, то печатаем последнее слово, удалив из него точки с запятой и двойные кавычки
- если строка содержит закрывающуюся фигурную скобку, мы выводим новую строку, в противном случае — пробел.
решение3
Итак, я видел, как люди отвечали разными и креативными решениями. Как энтузиаст регулярных выражений, я старался отвечать регулярными выражениями по мере необходимости.
Оказывается, ваш образец не является правильно сформированным документом из-за отсутствия точки с запятой в операторе Host Test.
Видите ли, здесь есть синтаксическая ошибка, которая делает недействительными два совершенно разумных выражения внутри оператора host Test: fixed-address и option.
Если вы хотите работать с правильно сформированными документами, а этот пример оказался ошибкой, то вы можете использовать:
host\s+[\w\-]+\s*\{(\s+hardware\s+ethernet\s+(([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2});)?(\s*fixed-address\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3});)?(\s*option\s+host-name\s+"(.*?)";)?\s*\}
Тогда строка замены будет иметь вид:
\2, \5, \7
С другой стороны, если вам нужно обратиться к документам, в которых отсутствуют точки с запятой, пожалуйста, поставьте вопросительный знак после каждой точки с запятой, которую вам нужно сделать необязательной.
Вы можете проверить свои варианты вhttps://regex101.com/
Дайте мне знать, если я ошибся. Удачи.