Excluir várias linhas em um arquivo

6

Geralmente eu encontro minhas respostas nas perguntas respondidas anteriormente, mas não desta vez (ou eu não entendo as respostas e não posso modificá-las para fazer o que eu quero que elas façam), então eu estou perguntando o meu primeiro pergunta aqui.

Meus arquivos de entrada parecem

# -*- coding: utf-8 -*-

[attachment]

[browser]


[changeset]

[components]
tracopt.versioncontrol.svn.svn_fs.subversionconnector = enabled
tracopt.versioncontrol.svn.svn_prop.subversionmergepropertydiffrenderer = enabled 
tracopt.versioncontrol.svn.svn_prop.subversionmergepropertyrenderer = enabled
tracopt.versioncontrol.svn.svn_prop.subversionpropertyrenderer = enabled

[header_logo]

[inherit]
file = /etc/trac/trac.ini

[logging]

Gostaria de remover todas as seções vazias, como anexo, navegador, changeset, header_logo e log. Eu só manteria as seções que não estão vazias. O arquivo de saída deve se parecer com

# -*- coding: utf-8 -*-

[components]
tracopt.versioncontrol.svn.svn_fs.subversionconnector = enabled
tracopt.versioncontrol.svn.svn_prop.subversionmergepropertydiffrenderer = enabled
tracopt.versioncontrol.svn.svn_prop.subversionmergepropertyrenderer = enabled
tracopt.versioncontrol.svn.svn_prop.subversionpropertyrenderer = enabled

[inherit]
file = /etc/trac/trac.ini

Isso deve acontecer em um script bash. Eu pensei em usar sed: procurando por um regex \[.+\]\n(\n)+(?=\[) , mas isso não parece funcionar com sed, porque eu deveria saber com antecedência quantas linhas o regex será e usar N de acordo. O regex também deve funcionar com EOF em vez do \[ final, mas provavelmente eu posso fazer isso se encontrar a maneira de fazer isso para o \[ .

Alguma ideia de como eu poderia fazer isso? Existe uma maneira melhor do que sed?

    
por trapangle 12.10.2015 / 15:00

2 respostas

8

É um pouco confuso com sed , mas é possível:

sed -n '
:start
/^\[/{
    h
  :loop
    n
    /^\[/b start
    /^$/b loop
    x;p;g
}
p'

-n significa imprimir nada por padrão. :start é apenas um rótulo para um futuro posterior. Nós combinamos as linhas que começam com [ e iniciamos um grupo ({...}) de comandos. Copiamos a linha para o espaço de espera (h). Nós obtemos a próxima linha (n). Se isso começa [ nós tivemos uma seção vazia, então goto (b) o começo novamente.

Se a linha estiver vazia (/ ^ $ /), lemos outra linha (goto loop). A linha não está vazia, então trocamos a linha com o cabeçalho da seção retida (x), imprimimos o cabeçalho da seção (p), recuperamos a linha atual (g) e continuamos fora do grupo de comandos para imprimir (p) a linha . Este último (p) também imprime cabeçalhos sem seção.

    
por 12.10.2015 / 15:20
2

Eu venho com o seguinte awk

BEGIN { empty=0 ; section = "" ; }
substr($0,1,1) == "[" { section = $0 ; next ; }
NF == 0 { if ( empty++ ) print ; section = "" ; next ; }
NF > 0  { if ( section != "" ) print section ; print ; section = "" ; }

para ser chamado com

awk -f pgm.awk infile > outfile

no entanto, como Terdon mencionou, pode ser melhor usar biblioteca, esse formato de arquivo não é confidencial, além da biblioteca tomar conta de cr , cr/nl e nl fim de linha.

    
por 12.10.2015 / 15:24