grep com linhas de continuação

3

Como posso grep / awk / sed um arquivo procurar algum padrão e imprimir a linha inteira (incluindo as linhas de continuação se a linha correspondente terminar com \ ?

Arquivo foo.txt contém:

something
whatever
thisXXX line \
    has a continuation line
blahblah
a \
multipleXXX \
continuation \
line

O que devo executar para obter (não necessariamente em uma linha, não necessariamente removendo vários espaços):

thisXXX line has a continuation line
a multipleXXX continuation line

BTW Estou usando bash e fedora21, então não precisa ser compatível com POSIX (mas apreciarei uma solução se for POSIX)

    
por Carlos Campderrós 04.06.2015 / 17:16

7 respostas

4

Outra abordagem usando o perl para remover novas linhas que são precedidas por \ e espaço em branco:

$ perl -pe 's/\\n/ /' file | grep XXX
thisXXX line      has a continuation line
a  multipleXXX  continuation  line

Para remover espaços extras, passe-o pelo sed:

$ perl -pe 's/\\n/ /' file | grep XXX | sed 's/  */ /g'
thisXXX line has a continuation line
a multipleXXX continuation line
    
por 04.06.2015 / 18:05
5

Com o POSIX sed:

$ sed -e '
:1
/\$/{N
  s/\n//              
  t1
}
/\/!d 
s/\[[:blank:]]*//g
' file
    
por 04.06.2015 / 18:18
5

Perl para o resgate:

perl -ne 'if (/\$/) { $l .= $_ }
          else { print $l, $_ if $l =~ /XXX/;
                 $l = "";
          }' foo.txt

$l funciona como um acumulador. -n processa a entrada linha por linha (cf. sed), se a linha terminar em uma barra invertida, ela será adicionada ao acumulador, se não, o acumulador mais a linha será impressa, desde que corresponda a XXX, e o acumulador seja esvaziado.

    
por 04.06.2015 / 17:24
4

Com pcregrep sem alterar a estrutura das linhas:

pcregrep -M '^(.|\\n)*XXX(.|\n)*?[^\]$' file
    
por 04.06.2015 / 18:32
4

Minha torção:

perl -0777 -ne '                           # read the entire file into $_
    s{ [[:blank:]]* \ \n [[:blank:]]* }   # join continued lines
     { }gx;
    print grep {/XXX/} split /(?<=\n)/     # print the matching lines
' foo.txt 
thisXXX line has a continuation line
a multipleXXX continuation line
    
por 04.06.2015 / 21:25
3

Eu diria que Perl é o mais simples aqui . Não é POSIX, embora esteja na instalação padrão da maioria dos unices não incorporados. Se você quiser POSIX, use o awk.

awk '{if (/\$/) printf "%s" $0; else print}'

Isso recolhe as linhas de continuação. Se você quiser encontrar padrões que se espalhem ao longo de uma continuação, canalize isso para grep. Se você quiser combinar apenas padrões ininterruptos, deixe o awk acumular linhas contínuas e fazer a correspondência.

awk '{
    if (sub(/\$/,"")) {
        line = line $0;
    } else {
        if (/XXX/) print;
        line = "";
    }
}'
    
por 05.06.2015 / 03:06
0

Esta é uma pequena melhoria para a solução Gilles awk (obrigado Gilles!), mas requer nawk:

nawk '{if (/\$/) {$0=substr($0,1,length($0)-2); printf "%s",$0} else print}'

Isso criará uma linha contínua se a linha for envolvida, mas não incluir o caractere "\" e espaço. (Eu achei isso útil quando grepping para instruções PATH desde o "\" pode levar a confusão ao interpretar os resultados.)

    
por 28.04.2016 / 20:56