Ich habe eine Liste mit einer Spalte, die ~ 100 Zeilen enthält, in denen einige Zeilen wiederholt werden, und mein Ziel ist es, eineSpezifischZeilen duplizieren und nureinskopieren, während die anderen Zeilen unverändert bleiben.
Ein Auszug der Dateien, an denen ich arbeite:
V(Mn9)
V(C1,H3)
V(Mn6)
V(Mn6)
V(C4,H6)
V(Mn9)
V(Mn9)
V(C1,Mn6)
V(C4,Mn9)
V(Mn6)
V(C1,C4)
C(Mn9)
C(Mn6)
C(C1)
C(C4)
C(Mn9)
C(Mn6)
V(C1,H2)
V(Mn9)
V(Mn6)
V(C4,H5)
Mein Ziel besteht darin, alle doppelten Zeilen zu entfernen, die C(Xx0-9) enthalten, eine davon zu belassen und V(Xxx..) beizubehalten.
Das Ergebnis, das ich suche:
V(Mn9)
V(C1,H3)
V(Mn6)
V(Mn6)
V(C4,H6)
V(Mn9)
V(Mn9)
V(C1,Mn6)
V(C4,Mn9)
V(Mn6)
V(C1,C4)
C(C1)
C(C4)
C(Mn9)
C(Mn6)
V(C1,H2)
V(Mn9)
V(Mn6)
V(C4,H5)
Ich habe den Befehl verwendet:
sed '0,/C(Mn9)/{/C(Mn9)/d}' inputfile.txt | sed '0,/C(Mn6)/{/C(Mn6)/d}'
und es funktioniert, ist aber nicht gut genug für die ganze Datei, da viel C(Xx1-50) vorhanden ist. Ich dachte daran, reguläre Ausdrücke zu verwenden, aber ich weiß nicht wie, deshalb brauche ich Ihre Hilfe.
Antwort1
$ awk '!(/^C\(..[0-9])$/ && seen[$0]++)' file
V(Mn9)
V(C1,H3)
V(Mn6)
V(Mn6)
V(C4,H6)
V(Mn9)
V(Mn9)
V(C1,Mn6)
V(C4,Mn9)
V(Mn6)
V(C1,C4)
C(Mn9)
C(Mn6)
C(C1)
C(C4)
V(C1,H2)
V(Mn9)
V(Mn6)
V(C4,H5)
Das Obige setzt voraus, dass Sie in Ihrer Beispieleingabe keine Leerzeichen vor/nach den sichtbaren Zeichen haben. Wenn ja, entfernen Sie sie, z. B.:
$ awk '{gsub(/^[[:space:]]+|[[:space:]]+$/,"")} !(/^C\(..[0-9])$/ && seen[$0]++)' file
V(Mn9)
V(C1,H3)
V(Mn6)
V(Mn6)
V(C4,H6)
V(Mn9)
V(Mn9)
V(C1,Mn6)
V(C4,Mn9)
V(Mn6)
V(C1,C4)
C(Mn9)
C(Mn6)
C(C1)
C(C4)
V(C1,H2)
V(Mn9)
V(Mn6)
V(C4,H5)
Antwort2
Ich schlage vor, sed
Zeilen im Wartebereich zu sammeln, um zu prüfen, ob sie schon einmal vorkamen:
sed -n 'H;G;/^\(C([^)]*)\).*\1 *\n/!P'
H
hängt die aktuelle Zeile an den Haltebereich anG
hängt den Haltebereich mit allen Zeilen, die wir je gesehen haben, an den Musterbereich anC([^)]*)
ist eines dieserC(…)
Muster, das^
es am Anfang der Zeile verankert und von umgibt\(…\)
, sodass es später als zurückverwiesen werden kann\1
. Wir brauchen\1 *\n
ein Muster mit der neuen Zeile (nach möglichen Leerzeichen), um zu vermeiden, dass die frisch angehängte Zeile am Ende übereinstimmt. Das gesamte Muster/^\(C([^)]*)\).*\1 *\n/
stimmt also mit einer Zeile mit einem doppelten übereinC(…)
, also nur, wenn dies!
nicht übereinstimmt,P
alles vor dem ersten Zeilenumbruch ausgeben (= ohne das angehängte Leerzeichen), während die Standardausgabe durch die-n
Option
Beachten Sie, dass dies je nach sed
Version und Dateigröße fehlschlagen kann, da sich mit der Zeit alle Zeilen im Speicher befinden.