Imprime texto entre tags (inclusive) se determinado texto for encontrado

1

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.

    
por AnthonyK 22.05.2014 / 09:57

4 respostas

3
perl -l -0777 -ne 'for (m{<Directory.*?</Directory>}gs) {print if /\+ExecCGI/}'

Ou com o GNU grep :

grep -zPo '(?s)<Directory(?:.(?!</Directory))*?\+ExecCGI.*?</Directory>'
    
por 22.05.2014 / 20:52
1

Você provavelmente também pode usar awk

awk 'BEGIN{RS="</Directory>\n"; ORS=RS} /\+ExecCGI/ {print}' file
    
por 23.05.2014 / 02:15
0

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

  • Sempre que vemos <Directory , definimos $flag = 1 .
  • Se $flag for verdadeiro (1 significa verdadeiro no contexto booleano), enviamos a entrada atual para a matriz @a .
  • Se virmos </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 .
  • Defina @a como matriz vazia para processar outro bloco.
por 22.05.2014 / 10:28
-1

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>
    
por 22.05.2014 / 10:23