perl -l -0777 -ne 'for (m{<Directory.*?</Directory>}gs) {print if /\+ExecCGI/}'
Ou com o GNU grep
:
grep -zPo '(?s)<Directory(?:.(?!</Directory))*?\+ExecCGI.*?</Directory>'
Eu tenho uma tarefa para extrair dados de vários servidores Apache. A tarefa é imprimir:
<Directory ...>
...
</Directory>
onde + ExecCGI está localizado dentro. Deixe-me dar um exemplo para ilustrar. Suponha que o arquivo de configuração do Apache tenha várias seções do Diretório, conforme indicado abaixo:
<Directory /var/www/site1/htdocs>
Options +ExecCGI
...
...
</Directory>
...
...
...
<Directory /var/www/site1/Promo>
Options -ExecCGI
...
...
</Directory>
Acima, gostaria apenas de obter a seguinte saída:
<Directory /var/www/site1/htdocs>
Options +ExecCGI
...
...
</Directory>
Eu pesquisei nos fóruns e encontrei posts em que as pessoas faziam perguntas sobre como imprimir uma seção inteira entre as tags (eu sei como fazer isso), ou para alterar determinado texto quando encontrado (novamente, eu sei como fazer isso).
Eu mudarei o + ExecCGI para -ExecCGI, mas as alterações precisam passar por um processo de revisão e, portanto, essa pergunta para que eu possa extrair esses dados.
Você provavelmente também pode usar awk
awk 'BEGIN{RS="</Directory>\n"; ORS=RS} /\+ExecCGI/ {print}' file
Se você pode usar perl
, aqui está uma solução:
$ perl -nle '
if (/<Directory/) {
$flag = 1;
}
push @a, $_ if $flag;
if (/<\/Directory/) {
$flag = 0;
if (grep {$_ =~ /\+ExecCGI/} @a) {
push @f, @a;
}
@a = ();
}
END {
print join "\n", @f;
}' file
<Directory /var/www/site1/htdocs>
Options +ExecCGI
...
...
</Directory>
Explicação
<Directory
, definimos $flag = 1
. $flag
for verdadeiro (1 significa verdadeiro no contexto booleano), enviamos a entrada atual para a matriz @a
. </Directory
, o que significa que concluímos o bloqueio, verificamos se o bloco contém +ExecCGI
string grep {$_ =~ /\+ExecCGI/
e, em seguida, enviamos @a
para @f
. @a
como matriz vazia para processar outro bloco. Aqui está um exemplo no Bash (Você deve ser capaz de fazer algo semelhante em praticamente qualquer idioma):
$ cat test.sh
#!/bin/bash
DIR=0
BLOCK=''
while read line
do
if [ $DIR -eq 0 ] ; then
if [[ $(echo $line | grep -i '<Directory') ]] ; then
DIR=1
BLOCK="$line"
fi
else
BLOCK="$BLOCK\n$line"
if [[ $(echo $line | grep -i '</Directory') ]] ; then
if [[ $(echo $BLOCK | grep -i 'Options.*+ExecCGI') ]] ; then
echo -e $BLOCK
fi
DIR=0
BLOCK=""
fi
fi
done
Basicamente, estamos apenas salvando o bloco à medida que avançamos e, em seguida, grepping
para ver se ele tem nosso padrão.
É muito simples, e é provável que tenha problemas com alguns casos de borda (se o seu arquivo de configuração contiver, pode-se confundir echo -e
, por exemplo), mas você pode expandir a idéia básica para lidar com eles.
Exemplo em uso:
$ cat test.conf
<Directory /var/www/site1/htdocs>
Options +ExecCGI
1
2
</Directory>
3
4
5
<Directory /var/www/site1/Promo>
Options -ExecCGI
6
7
</Directory>
<Directory /var/www/site1/htdocs>
Options -Whatever +ExecCGI
8
9
</Directory>
$ cat test.conf | bash test.sh
<Directory /var/www/site1/htdocs>
Options +ExecCGI
1
2
</Directory>
<Directory /var/www/site1/htdocs>
Options -Whatever +ExecCGI
8
9
</Directory>