Wie lösche ich jede zweite Zeile aus einer Datei?

25

Datei:

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

Erwartete Ausgabedatei:

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

Ich möchte, dass die Ausgabe so aussieht: Jede zweite Zeile wird gelöscht, aber es wird keine Lücke zwischen den Zeilen geben.

pmaipmui
quelle
5
Möchten Sie jede zweite Zeile oder alle Zeilen löschen, die "Kein Fehler aufgetreten" enthalten ? Was wäre, wenn zwei aufeinanderfolgende Zeilen "Kein Fehler aufgetreten" hätten ?
Tulains Córdova
1
@ user1598390 Ich denke ... in diesem Fall sollte grep -v "No error occurred" filedieser Befehl funktionieren ... was @paul geantwortet hat. In der Ausgabedatei gibt es keine Zeilen, die diesen Teil "Kein Fehler aufgetreten" enthalten.
Pmaipmui
1
Dann ist der Titel der Frage irreführend.
Tulains Córdova

Antworten:

36

Mit sed:

sed -e n\;d <file

Mit POSIX awk:

awk 'FNR%2' <file

Wenn Sie älter sind awk(wie oawk), benötigen Sie:

oawk 'NR%2 == 1' <file

Mit ex:

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

bearbeitet die Datei direkt.

  • g Markieren Sie einen globalen Befehl
  • /$/ Finde alle Zeilen
  • +d Löschen Sie die nächste Zeile
  • wq! Alle Änderungen speichern

Dieser Ansatz hat dasselbe Ideal wie der sedAnsatz. Löschen Sie jede nächste Zeile des aktuellen Zeilenanfangs ab Zeile 1.

Mit perl:

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

und perl6:

perl6 -ne '.say if $*IN.ins % 2' <file
perl6 -ne '.say if ++$ % 2' <file
cuonglm
quelle
Ja ... seine Arbeits ... :) ... erste funktioniert .... Ich habe auch die zweite versucht .. seine Erzählung `awk: Syntaxfehler line1 awk: in der Nähe von Linie 1' Rettung
pmaipmui
sed -en \; d <file ~ Yes its working @cuonglm ...
pmaipmui
1
Ich vermute , dass Sie verwenden n\;dstatt 'n;d'einen wertvollen Charakter zu sparen , sondern die Logik geht aus dem Fenster , wenn Sie unnötig die Verwendung von -eSchaltern und eine Datei Umleitung <!
Tom Fenech
1
@ Geek: Es ist nur eine kürzere Version von sed -e 'n;d', speichern Sie einen Charakter.
30.
1
@Geek: nBefehl zum Schreiben des Musterbereichs in die Standardausgabe, falls -nverwendet. Ersetzen Sie dann den Musterbereich durch die nächste Zeile. Hier wird jede ungerade Zeile gedruckt n, gerade Zeile dann in den Musterraum eingelesen, aber sofort per dBefehl gelöscht.
Donnerstag,
62

Das Beheben dieses Problems durch Löschen jeder zweiten Zeile kann fehleranfällig sein (z. B. wenn der Prozess manchmal zwei sinnvolle Zeilen statt einer generiert). Vielleicht ist es besser, den Müll herauszufiltern:

grep -v "No error occurred" file

Es kann als Filter ausgeführt werden, Sie können hier weitere Garbage Patterns hinzufügen und das Ergebnis verbessern.

paul
quelle
9
+1 für den Hinweis, dass manchmal die zweite Zeile wichtig ist!
Kaz Wolfe
12

Auf die Frage mit GNU sed:

sed '0~2d' file

löscht jede zweite Zeile, aber ich möchte Filterzeilen nach Inhalt anbieten:

sed '/Data/! d' file

oder mit dem gleichen Ergebnis

sed '/No error/d' file
Costas
quelle
sed '/ No error / d' Datei ~ gibt die gewünschte Ausgabe @Costas
pmaipmui
5
Beachten Sie, dass die letzten beiden Wege grep Datagrep -v 'No error'
verschlungen
5

Hier ist ein Weg mit sed:

sed -n 'p;n' filename

Ein anderer Weg mit GNU sed:

sed -n '1~2p' filename

Ausgabe von obigen Befehlen:

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
serenesat
quelle
Was meinst du mit sagen shortest way using sed?
Dienstag,
Was ist der Grund für das gKommando? sed -n 'p;n'ist genug.
Costas
@ Cuonglm: Ich meine, einfache Art und Weise zu tun. Übrigens hat dieses Wort entfernt. :)
serenesat
@Costas: Danke! Nur überprüft, es funktioniert ohne g. g aus dem Befehl entfernt. :)
serenesat
4

Sie können versuchen mit awk:

awk 'NR % 2 != 0' file

oder Sie können nur Zeilen drucken, die Folgendes enthalten Data inserted:

awk '$0 ~ /Data inserted/' file
Taliezin
quelle
Ich habe versucht, beide von Ihnen Antworten und beide arbeiten ... :)
Pmaipmui
3

Eine andere Antwort, du könntest vi / vim benutzen!

qdjddq

Wenn Ihre Datei beispielsweise 500 Zeilen lang ist, geben Sie Folgendes ein

250 @ d

Und dann schreiben und Typ beenden

: x

Oder wenn etwas schief geht und Sie nicht sparen möchten:

: q!

Erläuterung:

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'.
DJMcMayhem
quelle
2

Das geht ganz anders:

< file paste - - | cut -f1

Dies setzt voraus, dass die ungeraden Zeilen keine Tabulatoren enthalten. In diesem Fall müssen Sie ein anderes Trennzeichen auswählen, z. B. :hier:

< file paste -d: - - | cut -d: -f1
Digitales Trauma
quelle
1
Ich hatte dies im Hinterkopf, als ich die Frage zum ersten Mal sah ... Es wäre interessant, einen Geschwindigkeitstest sedmit einer riesigen Datei (z. B. 20-mil-Zeilen) durchzuführen . Wie auch immer, +1, aber um Kopfschmerzen zu vermeiden, wählen Sie ein Trennzeichen, das in einer Textdatei wahrscheinlich nicht vorkommt, wie $'\002'...
don_crissti
@don_crissti ja die Verwendung eines nicht druckbaren Zeichens für das Trennzeichen ist eine gute Idee. Und ja, das ist messbar schneller als die sed-Lösung. Ich habe eine Testdatei mit erstellt seq 100000000 > 100mil.txt. Die paste|cutLösung war nach etwa 7,5 Sekunden fertig, während die sedLösung fast 12 Sekunden benötigte . Scheint wiederholbar zu sein. grepist zwar am schnellsten. Ubuntu 14.04 mit Standard GNU Tools.
Digital Trauma
Ja, paste+ cutsind stark für ihren Job optimiert, so dass es nicht überraschend ist, dass ihre Kombination verdammt schnell ist ...
don_crissti
1

Eine andere Option (kürzer)

sed 'n; d' file
Michael Durrant
quelle
3
Es ist länger als meins sed n\;d, das Hinzufügen -eist nur meine Gewohnheit.
Dienstag,
0

Es löst auch das Problem, obwohl es etwas langsamer ist:

vim -c "%normal jdd" -c "wq" file
FloriOn
quelle