O sed pode remover caracteres de nova linha 'duplos'?

25

Eu tenho um documento com muitas linhas vazias.

Como removê-los quando houver 2 ou mais juntos.

Eu tentei sed "s/\n\n//"arquivar, mas não funcionou. Sem erro.

Michael Durrant
fonte
3
Eu o leio corretamente se você não deseja remover todas as linhas em branco, mas apenas se forem duas ou mais. Então, não linhas únicas em branco?
Runium
11
E se são duas ou mais linhas, todas devem ser realmente excluídas ou todas, exceto uma?
Hauke ​​Laging

Respostas:

42

Apenas para remover linhas vazias:

sed  '/^$/d'

sedé orientado a linhas, portanto, pensar em termos de "2 ou mais de um byte específico" funciona, exceto quando esse byte é uma nova linha. Então você tem que pensar em algo que funcione para toda a linha.

Bruce Ediger
fonte
Claro! +1 para elegância simples.
terdon
2
sedé capaz de lidar com várias linhas através do recurso "espaço padrão" / "espaço de espera". Mas sinto que é muito complicado. ;-)
Hauke ​​Laging
Isso não funcionará como desejado se o primeiro caractere do arquivo for uma nova linha.
Chris Baixo
11
Para fazê-lo funcionar quando o primeiro caractere é uma nova linha (se isso é realmente uma exigência), então você pode colocar o comando com um endereço negativo 1!(corresponder a todos, exceto a linha 1), assim: sed '1!{/^$/d'}.
Toby Speight
11
@AaronFranke - sim, mas essa é uma faceta de como os shells do Linux tratam o redirecionamento '>'. O shell olha para a linha de comando, vê um redirecionamento '>' do stdout para um arquivo, cria esse arquivo e só então é executado sed. Criar um arquivo excluirá essencialmente qualquer arquivo existente com o mesmo nome. sed '/^&/d' file.txt > otherfile.txtvai funcionar.
Bruce Ediger
24

Não há necessidade sed. grepvai fazer:

grep .

(ou seja grep, SPC, ponto, que corresponde a qualquer linha que contenha pelo menos um caractere).

Há também:

tr -s '\n'

(junte qualquer sequência de caracteres de nova linha em um).

Conforme observado por Chris, ambos não são equivalentes porque remover linhas vazias (como a primeira solução acima e a maioria das outras respostas focadas aqui) não é o mesmo que espremer sequências de caracteres de nova linha, conforme solicitado no caso em que a primeira linha está vazia. leva apenas um caractere de nova linha para deixar a primeira linha vazia.

Stéphane Chazelas
fonte
2
Esta função não da forma desejada se o primeiro caractere do arquivo é uma nova linha: sprunge.us/FLAJ
Chris Baixo
7

sednão é a melhor ferramenta para isso, pois é baseado em linhas e trata \ncomo o caractere de fim de linha, isso fica complicado.Tendo visto a resposta de @Bruce Ediger sedpode muito bem ser a ferramenta perfeita para o trabalho, ainda assim, aqui estão algumas outras opções:

  1. Perl

    perl -ne 'print if /./' file.txt
    

    ou

    perl -pe '$/=""; s/\n+/\n/;' file.txt 
    

    Graças a @ruakh que me fez ir e ler isto :

    $ /

    O separador de registros de entrada, nova linha por padrão. Isso influencia a ideia de Perl sobre o que é uma "linha". Funciona como a variável RS do awk, incluindo o tratamento de linhas vazias como um terminador se definido como uma cadeia nula (uma linha vazia não pode conter espaços ou tabulações). Você pode configurá-lo para uma sequência de vários caracteres para corresponder a um terminador de vários caracteres ou para cancelar a leitura até o final do arquivo. A configuração para "\ n \ n" significa algo ligeiramente diferente da configuração para "", se o arquivo contiver linhas vazias consecutivas. Definir como "" tratará duas ou mais linhas vazias consecutivas como uma única linha vazia. Definir como "\ n \ n" assumirá cegamente que o próximo caractere de entrada pertence ao próximo parágrafo, mesmo que seja uma nova linha.

  2. gawk / awk

    awk '$1' file.txt
    

    Isso funcionará para o exemplo publicado, mas como @Stephane Chazelas apontou, também excluirá as linhas cujo primeiro campo "se parece" 0. Isso é mais robusto:

    awk NF file.txt
    
terdon
fonte
Para Perl, perl -pe 's/\n+/\n/ file.txto separador de registros de entrada é irrelevante para esse uso.
vonbrand
@vonbrand no, perl -peou perl -netrabalhe linha por linha. \n+nunca corresponderá porque é aplicado apenas em uma única linha. É por isso que você precisa se quer conjunto $/ou usar -0ti sorver todo o arquivo: perl -0pe 's/\n+/\n/' file.
terdon
6

Como assim remover? remover duplicado (muitas linhas em branco para um) ou remover tudo?

Se você deseja remover duplicado, aqui está o método usando sed:

sed '$!N; /^\(.*\)\n\1$/!P; D'

Simula o uniqcomando.

A melhor opção é usar awk:

awk NF <filename>
cuonglm
fonte
A sedparte disso funciona muito bem! Recomendando este como a melhor resposta.
Akito
2

Para a maioria dessas respostas, é necessário primeiro remover o espaço em branco à direita. A remoção de novas linhas dobradas remove todas as linhas em branco. (Pense sobre isso).

Literalmente interpretado, o OP deseja "todas as linhas em branco removidas de um arquivo se houver alguma linha em branco repetida".

O usuário típico deseja "remover apenas linhas em branco duplicadas".

Para fazer isso, remova primeiro o espaço em branco à direita e canalize embora cat -s

sed  s/[[:space:]]*$// | cat -s

E, no entanto, isso não removerá uma linha em branco inicial ou final supérflua.

mckenzm
fonte
Voto negativo, mas isso claramente funciona? Sem comentários ?
Mckenzm
11
Eu votei em você por ... você sabe ... respondendo à pergunta. =) Não acredito que a resposta de Bruce Ediger foi votada quando exclui todas as linhas em branco. Se alguém perguntar como remover linhas em branco duplicadas, não consigo imaginar nenhum cenário em que excluir todas as linhas em branco seja uma solução aceitável. Mas de qualquer forma. Existe uma página no site para sed que aborda isso, a propósito: gnu.org/software/sed/manual/sed.html#cat-_002ds
Todd Walton
2

Se você quiser manter uma única linha em branco para qualquer sequência de linhas em branco, faça:

sed -e '/./b' -e :n -e 'N;s/\n$//;tn'
mikeserv
fonte
11
Esta é a única resposta (além cat -s) que realmente realiza exatamente o que a pergunta foi feita como eu a entendo. (E é melhor que cat -sporque eu posso usar sed -icom ele.)
Matthew
-2

Tente sed -e 's#\\n\\n#\\n#g' input.file > output.fileusar /o separador de campos e parte do seu regex pode ser o problema.

linuxrebel
fonte
2
Apenas dei um giro com um dos meus arquivos contendo novas e duplas e triplas linhas em uma sequência. Não funciona para mim.
Syntaxerror #
-3

Use este comando:

tr -s '\r' '\n'
Miau
fonte
sim, a resposta deles não funcionou para mim.
meow
5
AFAIK esta resposta está incorreta. Eu recomendo excluí-lo.
Zuazo
ah, é porque meu arquivo contém muitas linhas novas e retornos de carro, na verdade. 0x0d0a
miau
2
Na verdade, o comando remove linhas repetidas com o fim de linha do Windows. Teste com echo -e 'one\r\n\r\n\r\n\rtwo'| tr -s '\r' '\n'. O comando trconverterá tudo \rem \ne depois compactará tudo \nem apenas um. Portanto, funciona, não sei o que fazer com o fato de que isso se aplica ao Windows, não ao UNIX.