Como remover várias linhas em branco de um arquivo?

11

Eu tenho alguns arquivos de texto que eu uso para fazer anotações - apenas texto simples, geralmente apenas usando cat > > Arquivo. Ocasionalmente eu uso uma linha em branco ou duas (apenas retorne - o caractere de nova linha) para especificar um novo assunto / linha de pensamento. No final de cada sessão - antes de fechar o arquivo com ctrl-D - eu normalmente adiciono lotes (5-10) linhas em branco (chave de retorno) apenas para separar as sessões.

Isso obviamente não funciona muito bem, mas funciona para mim com esse propósito. Eu faço no entanto acabar com muitas linhas em branco desnecessárias, então eu estou procurando uma maneira de remover (a maioria) das linhas extras. Existe um comando do Linux (cortar, colar, grep, ...?) Que poderia ser usado diretamente com algumas opções? Alternativamente, alguém tem uma idéia para um script sed, awk ou perl (bem em qualquer linguagem de script realmente, embora eu prefira sed ou awk) que faria o que eu quero? Escrever algo em C ++ (o que eu realmente poderia fazer sozinho), parece um exagero ...

Caso 1: O que eu preciso é de um script / comando que remova mais de duas (3 ou mais) linhas em branco consecutivas e substitua-as por apenas duas linhas em branco. Embora seria bom se também pudesse ser ajustado para remover mais de uma linha (2 ou mais) e / ou substituir várias linhas em branco por apenas uma linha em branco.

Caso # 2: Eu também poderia usar um script / comando que removeria uma linha em branco simples entre duas linhas de texto, mas deixaria várias linhas em branco como estão (embora removendo uma das linhas em branco também seria aceitável).

PS: Sim, eu absolutamente deveria aprender script avançado (?) sed e awk, assim como perl ... já está muito atrasado. Mas como eu prometi a mim mesmo fazer exatamente isso depois de ler um bom livro sobre o Linux em 1995, eu não estou tão esperançoso.

    
por Baard Kopperud 17.04.2013 / 12:39

6 respostas

13

Caso 1:

awk '!NF {if (++n <= 2) print; next}; {n=0;print}'

Caso 2:

awk '!NF {s = s $0 "\n"; n++; next}
     {if (n>1) printf "%s", s; n=0; s=""; print}
     END {if (n>1) printf "%s", s}'
    
por 17.04.2013 / 13:03
15

Você pode usar uniq para recolher várias instâncias de linhas em branco em uma linha em branco, mas também recolherá linhas que contenham texto, se forem iguais e inferiores entre si.

    
por 17.04.2013 / 12:56
5

Caso 1:

perl -i -ane '$n=(@F==0) ? $n+1 : 0; print if $n<=2'

Caso 2:

perl -i -ane '$n=(@F==0) ? $n+1 : 0; print $n==2 ? "\n$_" : $n==1 ? "" : $_ '
    
por 10.05.2013 / 05:50
3

Você pode abordar o caso nº 1 assim com o GNU sed:

sed -r ':a; /^\s*$/ {N;ba}; s/( *\n *){2,}/\n\n/'

Ou seja, colete linhas vazias no espaço padrão e, se houver mais de três ou mais linhas, reduza-as para duas linhas.

Para unir linhas com espaçamento único, como no caso nº 2, você pode fazer assim:

sed -r '/^ *\S/!b; N; /\n *$/!b; N; /\S *$/!b; s/\n *\n/\n/'

Ou de forma comentada:

sed -r '
  /^ *\S/!b        # non-empty line
  N                # 
  /\n *$/!b        # followed by empty line
  N                # 
  /\S *$/!b        # non-empty line
  s/\n *\n/\n/     # remove the empty line
'
    
por 17.04.2013 / 14:46
0

Seguindo a sugestão de Anthon para usar "uniq" ...

Remova linhas em branco iniciais, duplicadas e anteriores.

# Get large random string.
rand_str=; while [[ ${#rand_str} -lt 40 ]]; do rand_str=$rand_str$RANDOM; done

# Add extra lines at beginning and end of stdin.
(echo $rand_str; cat; echo $rand_str) |

# Convert empty lines to random strings.
sed "s/^$/$rand_str/" |

# Remove duplicate lines.
uniq |

# Remove first and last line.
sed '1d;$d' |

# Convert random strings to empty lines.
sed "s/$rand_str//"

Em uma longa linha:

(rand_str=; while [[ ${#rand_str} -lt 40 ]]; do rand_str=$rand_str$RANDOM; done; (echo $rand_str; cat; echo $rand_str) | sed "s/^$/$rand_str/" | uniq | sed '1d;$d' | sed "s/$rand_str//")

Ou apenas use "cat -s".

Eu mudei de parênteses para chaves a fim de permanecer no shell atual contexto que eu assumo é mais eficiente. Observe que as chaves exigem ponto-e-vírgula após o último comando e precisam de um espaço para separação.

# Add extra blank lines at beginning and end.
# These will be removed in final step.
{ echo; cat; echo; } |

# Replace multiple blank lines with a single blank line.
cat -s |

# Remove first and last line.
sed '1d;$d'

Em uma única linha.

{ { echo; cat; echo; } | cat -s | sed '1d;$d'; }
    
por 27.03.2015 / 21:59
0

Esta solução também cuida das últimas linhas em branco no arquivo:

sed -r -n '
  /^ *$/!{p;b}  # non-blank line - print and next cycle
  h             # blank line - save it in hold space
  :loop
  $b end        # last line - go to end
  n             # read next line in pattern space
  /^ *$/b loop  # blank line - loop to next one
  :end          # pattern space has non-blank line or last blank line
  /^ *$/{p;b}   # last blank line: print and exit
  H;x;p         # non-blank line: print hold + pattern space and next cycle
'
    
por 16.12.2016 / 16:58