Como imprimir todas as linhas que não contêm uma string junto com linhas adjacentes?

4

Estou tentando envolver minha mente nessa tarefa. Eu quero da saída seguinte, para excluir todas as linhas que contêm Auto-installed: 1 e as 2 linhas antes. Eu estava ingenuamente pensando que grep -v -B2 string resolveria o problema ... desnecessário dizer, só piora a situação.

Este é o conteúdo:

Package: libopencore-amrwb0
Architecture: amd64
Auto-Installed: 1

Package: transfig
Architecture: amd64
Auto-Installed: 0

Package: xfig-libs
Architecture: amd64
Auto-Installed: 1

Package: xaw3dg
Architecture: amd64
Auto-Installed: 0

E é assim que os resultados aparecem:

Package: transfig
Architecture: amd64
Auto-Installed: 0

Package: xaw3dg
Architecture: amd64
Auto-Installed: 0

(note que linhas vazias não estão aparecendo, se ele não mostrar linhas vazias é uma vantagem, mas não é necessário, também os resultados devem incluir os pacotes que os valores auto-instalados são 0)

Eu sei que posso coincidir com as quebras de linha mas terminam não imprimindo nada ou imprimindo tudo, mas as linhas se quebram entre .

Qualquer solução é aceitável, não precisa ser grep ( ela pode ser emacs ).

    
por Braiam 18.11.2013 / 04:19

5 respostas

6

Não sei ao certo como seus dados são estruturados, mas se for exatamente como você mostra, que tal o seguinte:

grep -B2 'Auto-Installed: [^1]'

Isso pressupõe que cada sub-rotina inclua uma linha Auto-Installed , o que pode não estar correto.

Aqui está um programa awk que eu acho que faz exatamente como você pediu.

awk 'BEGIN{deleted=3}
     !deleted{printf "%s",l[NR%3]}
     deleted {--deleted}
     {l[NR%3]=/./?$0"\n":$0}
     /Auto-Installed: 1/{deleted=3}
     END{for(i=NR+deleted;i<NR+3;++i)printf "%s",l[i%3]}'
    
por 18.11.2013 / 04:44
3

Eu acho que isso vai fazer você

sed ':a
     $!N                          # slurp
     /Auto-Installed: 1/s/.*//    # kill all buffered on match
     $!{/\n.*\n/{P;D}}            # P/D any third line, D cycles w/o read
     $!ba                         # if no P/D, cycle w/o read anyway
    '
    
por 18.11.2013 / 04:34
3

Em vez de tentar lidar com excluí-los, por que não apenas selecionar as linhas opostas, o que você quer de qualquer maneira?

$ grep -B 2 "Auto-Installed: 0" data.txt 
Package: transfig
Architecture: amd64
Auto-Installed: 0

Excluindo seções com "Instalação automática: 1"

Se você quiser usar grep , mas usando sua lógica para abordar o problema em que exclui as seções que contêm "Auto-Installed: 1", não usei essa abordagem usando o instalação do PCRE dentro do GNU grep.

$ grep -B2 -P 'Auto-Installed: (?!1)' data.txt 

Exemplo

$ grep -B2 -P 'Auto-Installed: (?!1)' data.txt 
Package: transfig
Architecture: amd64
Auto-Installed: 0

O texto acima faz uso do recurso lookahead do Perl , (?!..) . Isso nos permite fazer a correspondência procurando por linhas que não contenham um valor de 1, após Auto-Installed: . Em seguida, informamos grep para exibir 2 linhas ( -B2 ) antes de "corresponder".

    
por 18.11.2013 / 04:42
2

O que você tem é, de fato, registros separados por linhas em branco. Em vez de codificar algumas análises frágeis que dependem da ordem e do número de linhas, use uma ferramenta como awk ou perl para processar registros separados por linhas em branco (modo de parágrafo).

awk -F '' '! /^Auto-Installed: 1$/'
    
por 19.11.2013 / 01:00
2

E aqui está o caminho obrigatório de Perl:

perl -000ne 'print unless /Auto-Installed: 1/' file

A mágica é o -000 , isso ativa o modo de parágrafo do Perl, o que faz com que ele divida os arquivos em parágrafos. Em outras palavras, os registros são separados por dois ou mais caracteres \n consecutivos.

Isso também irá imprimir a linha em branco entre as entradas, para se livrar disso, você pode executar

perl -000ne 'print unless /Auto-Installed: 1/' file | grep .
    
por 18.11.2013 / 16:40