
Preciso de uma regex para capturar registros de registro de host DHCP
Eu preciso analisar através de umdhcpd.confarquivo, para todas as reservas de host e, se possível, capture-as em um arquivo ou matriz Bash. Portanto, se uma reserva de host for definida da seguinte forma,
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";
}
Saída para arquivo ou array 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
Se faltar um dos três parâmetros, deixe em branco.
Mesmo que a expressão deva ser aplicada linha por linha, isso ainda é aceitável. Posso agrupar a expressão por meio de um script Bash que lê o arquivo de configuração linha por linha, é claro.
Responder1
Com parse_dhcp.awk
como
#!/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()}
então
awk -f parse_dhcp.awk dhcp.conf
Mais obscuramente, esse arquivo tem uma sintaxe Tcl válida, então só precisamos escrever a DSL para que possamos avaliar o arquivo como um script 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
e
tclsh parse_dhcp.tcl dhcp.conf
Responder2
As seguintes linhas Perl parecem quase produzir o que você deseja:
perl -ane 'print $F[-1] =~ s/[";]//gr unless /[{}]/; print /^$/ ? "\n" : " "'
mas temo que a entrada possa conter seções que você deseja ignorar completamente, portanto, são necessários mais ajustes:
perl -ane 'if (/host/ .. /}/) {
print $F[-1] =~ s/[";]//gr unless /[{}]/;
print /}/ ? "\n" : " "
}'
que significa
- se estivermos entre linhas contendo
host
e}
, processamos a entrada, caso contrário, a ignoramos. - se a linha atual não contém curvas, imprimimos a última palavra, removendo ponto e vírgula e aspas duplas dela
- se a linha contiver uma chave de fechamento, imprimimos uma nova linha, caso contrário, um espaço.
Responder3
Então, vi pessoas respondendo com soluções diferentes e criativas. Como entusiasta de regex, tentei responder com expressões regulares conforme necessário.
Acontece que sua amostra não é um documento bem formado devido ao ponto e vírgula ausente na instrução Host Test.
Veja, há um erro de sintaxe e isso invalida duas expressões perfeitamente razoáveis dentro da instrução Host Test: endereço fixo e opção.
Se você deseja trabalhar com documentos bem formados e este exemplo foi um erro, então você pode usar:
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*\}
A string de substituição será então:
\2, \5, \7
Por outro lado, se você precisar endereçar documentos sem ponto e vírgula, coloque um ponto de interrogação após cada ponto e vírgula que você deseja tornar opcional.
Você pode testar suas opções emhttps://regex101.com/
Deixe-me saber se cometi um erro. Boa sorte.