Ich habe Millionen von Datensätzen in einer Datei, die so aussehen
echo "NEW Cell"
grep "2553,24" out.2A25.20090308.64436.7.HDF.txt.text = 22.58 5.39 82.09 237
echo "NEW Cell"
grep "2555,20" out.2A25.20090308.64436.7.HDF.txt.text = 24.72 5.58 82.05 237
echo "NEW Cell"
grep "2557,20" out.2A25.20090308.64436.7.HDF.txt.text = 19.75 5.62 82.11 170
grep "2557,21" out.2A25.20090308.64436.7.HDF.txt.text = 24.34 5.58 82.13 120
grep "2558,22" out.2A25.20090308.64436.7.HDF.txt.text = 22.2 5.57 82.19 120
echo "NEW Cell"
grep "2560,22" out.2A25.20090308.64436.7.HDF.txt.text = 24.69 5.62 82.25 160
grep "2561,23" out.2A25.20090308.64436.7.HDF.txt.text = 24.74 5.60 82.30 120
echo "NEW Cell"
grep "2560,24" out.2A25.20090308.64436.7.HDF.txt.text = 19.38 5.54 82.30 170
echo "NEW Cell"
Jetzt möchte ich die Zeile mit „grep“ löschen, unter der Bedingung, dass es die EINZIGE Zeile zwischen den Zeilen ist, die „New Cell“ enthalten. Das heißt, wenn sich zwischen „New Cell“ eine Zeile mit „grep“ befindet, sollte diese Zeile gelöscht werden.
Wie macht man das?
Meine Ausgabe sollte so aussehen:
echo "NEW Cell"
grep "2557,20" out.2A25.20090308.64436.7.HDF.txt.text = 19.75 5.62 82.11 170
grep "2557,21" out.2A25.20090308.64436.7.HDF.txt.text = 24.34 5.58 82.13 120
grep "2558,22" out.2A25.20090308.64436.7.HDF.txt.text = 22.2 5.57 82.19 120
echo "NEW Cell"
grep "2560,22" out.2A25.20090308.64436.7.HDF.txt.text = 24.69 5.62 82.25 160
grep "2561,23" out.2A25.20090308.64436.7.HDF.txt.text = 24.74 5.60 82.30 120
Antwort1
AWK
Lösung:
awk 'NR==n{ if (/NEW Cell/) { f=0 } else print r ORS gr }
/NEW Cell/{ f=1; n=NR+2; r=$0; next }
f && n-NR==1 && /^grep /{ gr=$0; next }1' file
/NEW Cell/{ f=1; n=NR+2; r=$0; next }
- auf der Begegnungslinie mitNEW Cell
f=1
= Aktiv-Flag setzenf=1
n=NR+2
n
- als maximale Anzahl der zu verarbeitenden Folgezeilen festlegen (2 nächste Zeilen)r=$0
- die Linie erfassennext
- zum nächsten Datensatz springen
f && n-NR==1 && /^grep /
- beim Auffinden der zweiten Zeile (gesichert durch ), die mit dem Schlüsselwortn-NR==1
beginntgrep
gr=$0; next
-grep
Zeile erfassen und zum nächsten (dritten) Datensatz springen
NR==n{ if (/NEW Cell/) { f=0 } else print r ORS gr }
- beim Erreichen der 3. entscheidenden Linie (gewährleistet durchNR==n
)if (/NEW Cell/) { f=0 }
- wenn die 3. Zeile unter dem verarbeiteten Abschnitt Folgendes enthältNEW Cell
: - aktuelle Verarbeitung zurücksetzen mitf=0
(alle zuvor erfassten Zeilen werden übersprungen)else print r ORS gr
- andernfalls alle zuvor erfassten Zeilen drucken
Die Ausgabe:
echo "NEW Cell"
grep "2557,20" out.2A25.20090308.64436.7.HDF.txt.text = 19.75 5.62 82.11 170
grep "2557,21" out.2A25.20090308.64436.7.HDF.txt.text = 24.34 5.58 82.13 120
grep "2558,22" out.2A25.20090308.64436.7.HDF.txt.text = 22.2 5.57 82.19 120
echo "NEW Cell"
grep "2560,22" out.2A25.20090308.64436.7.HDF.txt.text = 24.69 5.62 82.25 160
grep "2561,23" out.2A25.20090308.64436.7.HDF.txt.text = 24.74 5.60 82.30 120
Antwort2
Kompakte Lösung mit sed
:
sed '/NEW Cell/!{H;d;};x;/\n.*\n/!d'
Wenn die Zeile nichts enthält, NEW Cell
führen Sie die Ausführung aus H
, um die Zeile an den Haltebereich anzuhängen und d
die Verarbeitung für diese Zeile zu stoppen.
Weitere Befehle werden also nur auf NEW Cell
Zeilen angewendet: Das x
vertauscht Musterraum und Halteraum, dadurch steht die Zeile nun im Halteraum und weitere Zeilen können angehängt werden, während der Musterraum alles aufnimmt, was an die letzte NEW Cell
Zeile angehängt wurde. Deine Anforderung ist, dass zwischen den Zeilen mehr als eine Zeile steht NEW Cell
, also müssen im Musterraum mindestens zwei Zeilenumbrüche stehen. Wenn nicht, lösche es ohne Ausgabe: /\n.*\n/!d
.
Antwort3
Mit rudimentären awk
...
Version 1 löscht nur grep
Zeilen, die der Beschreibung des OP folgen:
awk '/^grep/ { if (f) { if (length(s) > 0) { print s; s="" } print } \
else { f=1; s=$0 } } ! /^echo/ { print; f=0 } \
! /^echo/ && ! /^grep/ { print }' inputfile
Version 2 löscht einzelne grep
Zeilen sowie vorangehende Nicht-Grep-Zeilen, die der Beispielausgabe des OP folgen:
awk '/^grep/ { if (f) { if (length(s) > 0) { print s; s="" } print } \
else { f=1; s=s "\n" $0 } } /^echo/ { s=$0; f=0 } \
! /^echo/ && ! /^grep/ { print }' inputfile
Lesbare Form der Version 2...
/^grep/ {
if (found) { # found==true : already encountered first grep line
if (length(save) > 0) {
print save
save=""
}
print
} else {
found=1
save=save "\n" $0 # append the first grep line to saved preceding line
}
}
/^echo/ {
save=$0 # save this line for possible later printing
found=0
}
# print anything else
! /^echo/ && ! /^grep/ { print }
Diese lange Form kann ausgeführt werden, indem der Inhalt in eine Datei (z. B. awkfile
) eingefügt und ausgeführt wird awk -f awkfile inputfile
.
Antwort4
gawk '
/\n.+\n/{
printf("%s%s", RS, $0);
}' RS='echo "NEW Cell"\n' input.txt
Erläuterung:
RS='echo "NEW Cell"\n'
-RS
ist das Trennzeichen für den Eingabedatensatz, standardmäßig ein Zeilenumbruch. Jetzt wurde es in geändertecho "NEW Cell"\n
, sodass alle Vorkommen dieser Zeichenfolge entfernt werden und alle Zeichen dazwischen zum Datensatzelement werden./\n.+\n/{
- nur für Datensätze, die diesem Muster entsprechen - Zeilenumbruch, ein oder mehrere Zeichen, Zeilenumbruch. Es stimmt also nur mit mehrzeiligen Datensätzen überein, der einzeilige Datensatz stimmt nicht überein, da er nur einen hat\n
.printf("%s%s", RS, $0);
- druckt den Datensatz, dem einRS
(echo "NEW Cell"\n
) vorangestellt ist.
Ausgabe
echo "NEW Cell"
grep "2557,20" out.2A25.20090308.64436.7.HDF.txt.text = 19.75 5.62 82.11 170
grep "2557,21" out.2A25.20090308.64436.7.HDF.txt.text = 24.34 5.58 82.13 120
grep "2558,22" out.2A25.20090308.64436.7.HDF.txt.text = 22.2 5.57 82.19 120
echo "NEW Cell"
grep "2560,22" out.2A25.20090308.64436.7.HDF.txt.text = 24.69 5.62 82.25 160
grep "2561,23" out.2A25.20090308.64436.7.HDF.txt.text = 24.74 5.60 82.30 120