Sed può rimuovere i caratteri di "nuova" linea doppia?


25

Ho un documento con molte righe vuote.

Come posso rimuoverli quando ce ne sono 2 o più insieme.

Ho provato il sed "s/\n\n//"file ma non ha funzionato. Nessun errore.


3
Ti leggo correttamente se non vuoi rimuovere tutte le righe vuote, ma solo se sono due o più. Quindi non singole righe vuote?
Runium,

1
E se sono due o più righe, devono davvero essere cancellate tutte o solo tutte tranne una?
Hauke ​​Laging,

Risposte:


42

Solo per rimuovere le righe vuote:

sed  '/^$/d'

sedè orientato alla linea, quindi pensare in termini di "2 o più di un particolare byte" funziona tranne quando quel byte è una nuova riga. Quindi devi pensare a qualcosa che funziona per l'intera linea.


Ovviamente! +1 per una semplice eleganza.
terdon

2
sedè in grado di gestire più linee tramite la sua funzione "spazio modello" / "spazio di attesa". Ma penso che sia troppo complicato. ;-)
Hauke ​​Laging

Questo non funzionerà come desiderato se il primo carattere del file è una nuova riga.
Chris Down,

1
Per farlo funzionare, quando il primo carattere è un ritorno a capo (se questo è davvero un requisito), allora si può racchiudere il comando con un indirizzo negativo 1!(abbinare tutti tranne la linea 1), in tal modo: sed '1!{/^$/d'}.
Toby Speight,

1
@AaronFranke - sì, ma è un aspetto di come le shell Linux trattano il reindirizzamento '>'. La shell esamina la riga di comando, vede un reindirizzamento '>' di stdout su un file, crea quel file e solo allora viene eseguito sed. La creazione di un file eliminerà essenzialmente qualsiasi file esistente con lo stesso nome. sed '/^&/d' file.txt > otherfile.txtfunzionerà.
Bruce Ediger,

24

Non c'è bisogno di sed. grepandrà bene:

grep .

(ovvero grepSPC, punto, che corrisponde a qualsiasi riga contenente almeno un carattere).

C'è anche:

tr -s '\n'

(stringi qualsiasi sequenza di caratteri di nuova riga in uno).

Come notato da Chris, entrambi non sono equivalenti perché rimuovere le righe vuote (come la prima soluzione sopra e la maggior parte delle altre risposte si concentra su qui) non è lo stesso di spremere sequenze di caratteri di nuova riga come richiesto nel caso in cui la prima riga è vuota in quanto richiede solo un carattere di nuova riga iniziale per rendere vuota la prima riga.


2
Questo non funzionerà come desiderato se il primo carattere del file è una nuova riga: sprunge.us/FLAJ
Chris Down

7

sednon è lo strumento migliore per questo, dal momento che è basato sulla linea e considera \nil carattere di fine linea questo diventa complicato.Avendo visto la risposta di @Bruce Ediger sedpotrebbe essere lo strumento perfetto per il lavoro, tuttavia, ecco alcune altre opzioni:

  1. Perl

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

    o

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

    Grazie a @ruakh che mi ha fatto andare a leggere questo :

    $ /

    Il separatore del record di input, newline per impostazione predefinita. Ciò influenza l'idea di Perl di cosa sia una "linea". Funziona come la variabile RS di awk, incluso il trattamento di righe vuote come terminatore se impostato sulla stringa null (una riga vuota non può contenere spazi o tabulazioni). È possibile impostarlo su una stringa a più caratteri per abbinare un terminatore a più caratteri o su undef per leggere fino alla fine del file. Impostandolo su "\ n \ n" significa qualcosa di leggermente diverso dall'impostazione su "", se il file contiene righe vuote consecutive. L'impostazione su "" considera due o più righe vuote consecutive come un'unica riga vuota. L'impostazione su "\ n \ n" presuppone ciecamente che il carattere di input successivo appartenga al paragrafo successivo, anche se si tratta di una nuova riga.

  2. gawk / awk

    awk '$1' file.txt
    

    Funzionerà con l'esempio pubblicato ma, come sottolineato da @Stephane Chazelas , eliminerà anche le righe il cui primo campo "sembra" 0. Questo è più robusto:

    awk NF file.txt
    

Per Perl, perl -pe 's/\n+/\n/ file.txtlo farà, il separatore del record di input è irrilevante per questo uso.
vonbrand,

@vonbrand no, perl -peoppure perl -nelavorare riga per riga. \n+non corrisponderà mai perché viene applicato solo su una singola riga. Ecco perché è necessario o insieme $/o utilizzare -0ti Slurp il file intero: perl -0pe 's/\n+/\n/' file.
terdon

6

Cosa intendi per rimuovere? rimuovere il duplicato (molte righe vuote in una) o rimuovere tutto?

Se vuoi rimuovere i duplicati, ecco il metodo che usa sed:

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

Simula il uniqcomando.

La scelta migliore sta usando awk:

awk NF <filename>

La sedparte di questo funziona alla grande! Raccomando questo come la migliore risposta.
Akito

2

Per la maggior parte di queste risposte è innanzitutto necessario rimuovere gli spazi bianchi finali. La rimozione di nuove righe raddoppiate rimuove tutte le righe vuote. (Pensaci).

Interpretato letteralmente l'OP vuole "tutte le righe vuote rimosse da un file se ci sono righe vuote ripetute".

L'utente tipico desidera "rimuovere solo le righe vuote duplicate".

Per fare ciò, spoglia prima lo spazio bianco finale e pipe anche se cat -s

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

Eppure questo non rimuoverà una linea vuota iniziale o finale superflous.


Downvoted, ma questo funziona chiaramente? Nessun commento ?
mckenzm,

1
Ti ho votato per ... sai ... rispondere alla domanda. =) Non riesco a credere che la risposta di Bruce Ediger sia stata annullata quando cancella ogni riga vuota. Se qualcuno chiede come rimuovere le righe vuote duplicate, non riesco a immaginare uno scenario in cui l'eliminazione di tutte le righe vuote sarebbe una soluzione accettabile. Ma comunque. C'è una pagina sul sito Web di sed che tratta questo, a proposito: gnu.org/software/sed/manual/sed.html#cat-_002ds
Todd Walton,

2

Se si desidera mantenere un'unica riga vuota per una determinata sequenza di righe vuote è possibile:

sed -e '/./b' -e :n -e 'N;s/\n$//;tn'

1
Questa è l'unica risposta (oltre cat -s) che in realtà realizza esattamente ciò che la domanda posta come la capisco. (Ed è meglio che cat -sperché posso usarlo sed -i.)
Matthew,

-2

Prova a sed -e 's#\\n\\n#\\n#g' input.file > output.fileutilizzare /sia il separatore di campo che parte del regex potrebbero essere il problema.


2
Ho appena fatto un giro con uno dei miei file che contengono sequenze doppie e triple in una sequenza. Per me non funziona affatto.
syntaxerror

-3

Usa questo comando:

tr -s '\r' '\n'

sì, la loro risposta non ha funzionato per me.
miao

5
AFAIK questa risposta non è corretta. Ti consiglio di cancellarlo.
zuazo,

oh, è perché il mio file contiene molte nuove righe e ritorni a capo. 0x0d0a
miao il

2
In realtà, il comando rimuove le righe ripetute con la fine della riga di Windows. Prova con echo -e 'one\r\n\r\n\r\n\rtwo'| tr -s '\r' '\n'. Il comando trtradurrà tutto \rin \ne quindi comprimerà tutto \nin uno solo. Quindi, funziona, non sono sicuro di cosa fare con il fatto che questo si applica a Windows, non a UNIX.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.