Wie entferne ich doppelte Zeilen mit awk, während ich leere Zeilen behalte?

13

Der folgende awkBefehl entfernt alle doppelten Zeilen wie hier erklärt :

awk '!seen[$0]++'

Wenn der Text Leerzeilen enthält, werden alle bis auf eine Leerzeile gelöscht.

Wie kann ich alle leeren Zeilen behalten, während ich alle nicht leeren doppelten Zeilen lösche und nur verwende awk? Bitte fügen Sie auch eine kurze Erklärung bei.

Serge Stroobandt
quelle

Antworten:

28

Eine andere Möglichkeit ist zu prüfen NF, zB:

awk '!NF || !seen[$0]++'
Thor
quelle
11

Alternative

awk '!/./ || !seen[$0]++' file

Der Haupttrick ist der gleiche, seen[$0]++erstellt einen Eintrag im seenassoziativen Array, dessen Schlüssel die aktuelle Zeile ( $0) ist. Daher ist !seen[$0]++false, wenn diese Zeile bereits gesehen wurde. Das /./prüft, ob die Zeile irgendwelche nicht leeren Zeichen enthält, also !/./passt es zu nicht leeren Zeilen. In Kombination || !seen[$0]++werden alle doppelten Zeilen mit Ausnahme der leeren ignoriert und der Rest gedruckt.

terdon
quelle
Ich denke, das hätte die akzeptierte Antwort sein sollen. +1 zur Erklärung!
SS Anne
5
awk '/^[[:blank:]]*$/ { print; next; }; !seen[$0]++'

Alles, was Sie tun müssen, ist, zuerst nach einer leeren (wirklich leeren oder nur leeren) Zeile zu suchen.

Hauke ​​Laging
quelle
5

Hier ist eine andere awkLösung, die der Antwort von @ Thor ähnelt und weniger präzise, ​​aber effizienter ist:

awk '!NF {print;next}; !($0 in a) {a[$0];print}' file

Damit haben wir nur geprüft, ob a[$0]es existiert oder nicht. Wenn nicht, initialisieren Sie es und drucken Sie es aus. In diesem Fall haben wir keinen Bezug, Zuordnung zu, a[$0]falls vorhanden.

cuonglm
quelle
Ich habe mit meiner 288-Zeilen-Testdatei keinen signifikanten Zeitunterschied gemessen. Ihr Code wird jedoch mit Sicherheit als der am besten lesbare ausgezeichnet.
Serge Stroobandt