Come eliminare ogni seconda riga da un file?


25

File:

Data inserted into table. Total count 13
No error occurred
Data inserted into table. Total count 45
No error occurred
Data inserted into table. Total count 14
No error occurred
Data inserted into table. Total count 90
No error occurred

File di output previsto:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

Voglio che l'output appaia in questo modo: ogni seconda riga verrà eliminata ma non ci sarà spazio tra le righe.


5
Vuoi eliminare ogni seconda riga o tutte le righe che contengono "Nessun errore verificato" ? E se due righe consecutive avessero "Nessun errore" ?
Tulains Córdova,

1
@ user1598390 Penso ... in tal caso grep -v "No error occurred" filequesto comando dovrebbe funzionare ... cosa ha risposto @paul. Nel file di output non ci saranno righe contenenti "Nessun errore" in questa parte.
pmaipmui,

1
Quindi il titolo della domanda è fuorviante.
Tulains Córdova,

Risposte:


36

Con sed:

sed -e n\;d <file

Con POSIX awk:

awk 'FNR%2' <file

Se hai più vecchi awk(come oawk), hai bisogno di:

oawk 'NR%2 == 1' <file

Con ex:

$ ex file <<\EX
:g/$/+d
:wq!
EX

modificherà il file sul posto.

  • g contrassegnare un comando globale
  • /$/ abbina ogni riga
  • +d elimina la riga successiva
  • wq! salva tutte le modifiche

Questo approccio condivide lo stesso ideale con l' sedapproccio, elimina ogni riga successiva della riga corrente a partire dalla riga 1.

Con perl:

perl -ne 'print if $. % 2' <file

e perl6:

perl6 -ne '.say if $*IN.ins % 2' <file
perl6 -ne '.say if ++$ % 2' <file

Sì ... funziona ... :) ... il primo funziona .... ho anche provato il secondo ... sta dicendo "awk: errore di sintassi line1 awk: salvataggio in linea vicino alla linea 1"
pmaipmui

sed -en \; d <file ~ Sì funziona @cuonglm ...
pmaipmui

1
Immagino che tu abbia usato n\;dinvece di 'n;d'salvare un personaggio prezioso, ma quella logica esce dalla finestra quando usi inutilmente l' -eopzione e un reindirizzamento dei file <!
Tom Fenech,

1
@Geek: è solo una versione più breve di sed -e 'n;d', ti salva un personaggio.
cuonglm,

1
@Geek: ncomando se -nsi utilizzava lo spazio modello sull'output standard , quindi sostituire lo spazio modello con la riga successiva. Ecco ogni riga dispari che verrà stampata da n, la linea pari quindi letta nello spazio del modello ma cancellata immediatamente con il dcomando`.
cuonglm,

62

Risolvere questo problema eliminando ogni seconda riga può essere soggetto a errori (ad esempio, quando il processo a volte genera due righe significative anziché una). Potrebbe essere meglio filtrare la spazzatura:

grep -v "No error occurred" file

Può essere eseguito come filtro, è possibile aggiungere più schemi di immondizia qui e migliorare il risultato.


9
+1 per sottolineare che a volte la seconda riga è importante!
Kaz Wolfe,

12

Rispondendo alla domanda, con GNU sed:

sed '0~2d' file

eliminerà ogni seconda riga ma mi piacerebbe offrire linee di filtro in base al suo contenuto:

sed '/Data/! d' file

o con lo stesso risultato

sed '/No error/d' file

sed '/ Nessun errore / d' file ~ fornisce l'output desiderato @Costas
pmaipmui

5
Nota che gli ultimi due sono modi contorti di scrivere grep Dataegrep -v 'No error'
Stéphane Chazelas il

5

Ecco un modo usando sed:

sed -n 'p;n' filename

Un altro modo con GNU sed:

sed -n '1~2p' filename

Uscita dai comandi sopra:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

Cosa intendi quando dici shortest way using sed?
cuonglm,

Qual è il motivo al gcomando? sed -n 'p;n'è abbastanza.
Costas,

@cuonglm: intendo dire un modo semplice di fare. A proposito rimossa quella parola. :)
serenesat,

@Costas: grazie! Appena controllato, funziona senza g. rimosso g dal comando. :)
serenesat,

4

Puoi provare con awk:

awk 'NR % 2 != 0' file

oppure puoi stampare solo righe contenenti Data inserted:

awk '$0 ~ /Data inserted/' file

Ho provato entrambe le risposte ed entrambi funzionano ... :)
pmaipmui,

3

Un'altra risposta, potresti usare vi / vim!

qdjddq

E poi se il tuo file era di 500 righe (ad esempio) digita

250 @ d

E poi per scrivere e uscire dal tipo

:X

O se qualcosa va storto e non vuoi salvare:

: Q!

Spiegazione:

q      #Start Recording
 d     #Put the recording into register 'd'
  j    #Move the cursor down
   dd  #Delete the line
     q #Stop recording


250    #Number of repeats
   @d  #Playback the recording in register 'd'.

2

Ecco un modo abbastanza diverso di farlo:

< file paste - - | cut -f1

Ciò presuppone che le righe dispari non contengano schede. In tal caso, dovrai scegliere un altro carattere di separazione, ad esempio :qui:

< file paste -d: - - | cut -d: -f1

1
Ho avuto questo in mente quando ho visto la domanda per la prima volta ... Sarebbe interessante eseguire un test di velocità sedcon un file enorme (ad esempio 20 milioni di righe). Comunque, +1 ma davvero, per evitare il mal di testa, scegli un delimitatore che è improbabile che si verifichi in un file di testo, come $'\002'...
don_crissti

@don_crissti sì, l'uso di un carattere non stampabile per il separatore è una buona idea. E sì, questo è misurabilmente più veloce della soluzione sed. Ho creato un file di prova con seq 100000000 > 100mil.txt. La paste|cutsoluzione è terminata in circa 7,5 secondi, rispetto a quasi 12 per la sedsoluzione. Sembra essere ripetibile. grepè più veloce però. Ubuntu 14.04 con strumenti GNU standard.
Trauma digitale

Sì, paste+ cutsono fortemente ottimizzati per il loro lavoro, quindi la loro combinazione è sorprendentemente veloce ...
don_crissti

1

Un'altra opzione (più breve)

sed 'n; d' file

3
È più lungo del mio sed n\;d, l'aggiunta -eè solo la mia abitudine.
cuonglm,

0

Risolve anche il problema, anche se è un po 'più lento:

vim -c "%normal jdd" -c "wq" file
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.