Löschen des vorletzten Zeichens in jeder Zeile - mit sed

7

Wie lösche ich das Zeichen vor dem letzten Zeichen in jeder Zeile einer Datei?

Ich habe versucht sed 's/.$//' myfile1.txt, das letzte Zeichen jeder Zeile in zu entfernen myfile1.txt, bin mir aber nicht sicher, wie ich das vorletzte Zeichen in jeder Zeile löschen soll.

Anurag Singh
quelle

Antworten:

10

Du kannst tun:

sed -E 's/.(.)$/\1/' file.txt  

So bearbeiten Sie die Datei ohne Sicherung:

sed -Ei 's/.(.)$/\1/' file.txt 

So bearbeiten Sie die Datei an Ort und Stelle, wobei die Originaldatei mit der .bakErweiterung gesichert wird :

sed -Ei.bak 's/.(.)$/\1/' file.txt 

POSIX-ly:

sed 's/.\(.\)$/\1/' file.txt
heemayl
quelle
8

Um den portablen Befehl vollständig zu erklären (da jemand gefragt hat), damit JEDER dies verstehen kann:

sed 's/.\(.\)$/\1/' file.txt

Erstens das "Offensichtliche": Diese Zeile besteht aus einem Befehlsnamen ( sed) und zwei separaten Argumenten, die von der Shell an diesen Befehl übergeben werden. Die einfachen Anführungszeichen werden von der Shell entfernt, was also sedals Argumente "sieht":

s/.\(.\)$/\1/

und

file.txt

Da keines der Argumente sedmit einem Bindestrich beginnt, wird keines davon als Option interpretiert.

Das erste Argument wird als ein auszuführender Bearbeitungsbefehl interpretiert, und alle anderen Argumente (in diesem Fall nur das eine file.txt) werden als Namen von Dateien interpretiert, aus denen der vom Bearbeitungsbefehl zu bearbeitende Text gelesen werden soll (das erste Argument). .

(Beachten Sie, dass der bearbeitete Text in seddie "Standardausgabe" geschrieben wird - das heißt, zurück zu Ihrem Terminal, Ihrem Befehlszeilenfenster -, er wird nicht zurück in die Datei geschrieben.)

file.txtmuss ein Dateiname einer Datei sein, die sich im Verzeichnis befindet, das das "aktuelle Arbeitsverzeichnis" Ihrer Shell ist, wenn Sie diesen sedBefehl ausführen . (Wenn Sie möchten, dass der Befehl mit derselben Datei funktioniert, unabhängig davon, wie das aktuelle Arbeitsverzeichnis Ihrer Shell lautet, wenn Sie den Befehl ausführen, lesen Sie die "absoluten Pfade".)


Jetzt dekonstruieren wir den Bearbeitungsbefehl selbst:

s/.\(.\)$/\1/

Der Bearbeitungsbefehl beginnt mit dem Buchstaben s"Ersatz". Vom Zeichen nach dem "s" ( /in diesem Fall) bis zur nächsten Instanz desselben Zeichens ( /wieder) ist das Muster, das ersetzt werden soll. Mit anderen Worten, es gibt an, wie der zu ersetzende Text "aussehen" soll - es gibt an, sedwie "zu wissen" ist, wann es Text gefunden hat, der ersetzt werden soll (ersetzt werden soll).

Das Muster in diesem Fall ist:

.\(.\)$

(Der richtige Begriff anstelle von "Muster" ist eigentlich Regex , ursprünglich kurz für "regulärer Ausdruck". Ich werde hier nicht auf das umfassendere Thema Regex eingehen.)

Diese Regex beginnt mit einem Punkt ( .), der ein "Platzhalter" mit der Bedeutung "ein einzelnes Zeichen" ist. Es entspricht (beschreibt, symbolisiert) jedem einzelnen Textzeichen.

Der Backslash ( \) wird häufig in Shell-Befehlen und regulären Ausdrücken als "Escape" -Zeichen verwendet. In der Regel bedeutet dies , dass sie entweder entfernt die besondere Bedeutung des Zeichens , die es folgt, oder sie fügt eine besondere Bedeutung für die folgenden Zeichen.

In diesem Fall werden die Klammern (beide (und )) maskiert (dh mit einem Backslash versehen), um eine besondere Bedeutung hinzuzufügen . Die besondere Bedeutung des entkam Klammer in einer sedregex ist , dass , was Text den Teil der Regex paßt in den Klammern ist „ so “ speziell und kann zurückverwiesen auf. Wir werden später darauf zurückkommen (wenn wir auf diese Klammergruppierung zurückgreifen).

Der Punkt ( .) in den Klammern stimmt wieder mit einem einzelnen Zeichen überein.

Das Dollarzeichen ( $) wird als Anker bezeichnet und entspricht dem Ende einer Textzeile. Ohne diesen Anker würde der reguläre Ausdruck einfach mit zwei beliebigen Zeichen übereinstimmen (insbesondere mit den ersten beiden Zeichen in jeder aus der aufgerufenen Datei eingelesenen Textzeile file.txt) und (aufgrund der maskierten Klammern) seddas zweite "notieren" der beiden Zeichen, auf die später Bezug genommen wird.

Da der reguläre Ausdruck am Ende der Zeile verankert ist , müssen die beiden Punkte mit den letzten beiden Zeichen in jeder Textzeile übereinstimmen (und das letzte Zeichen wird zur späteren Bezugnahme notiert).

Der nächste Teil des s(Ersatz-) Befehls reicht von der zweiten Instanz des folgenden Zeichens s(in diesem Fall einem Schrägstrich /) bis zur dritten Instanz des folgenden Zeichens s. Dies wird als Ersatzmuster bezeichnet. Es legt fest , was sedsollte anstelle von setzen den Text durch das angepasste Suchmuster (die reguläre Ausdrücke).

In diesem Fall lautet das Ersatzmuster:

\1

Auch hier wird der Backslash verwendet, um dem folgenden Zeichen zu entkommen , und in diesem Fall wird erneut eine spezielle Bedeutung hinzugefügt, anstatt eine spezielle Bedeutung zu entfernen.

Ein Backslash gefolgt von einer Ziffer (von 1 bis 9) wird als Backreference bezeichnet. Dies bezieht sich auf den Text, der in der Klammergruppierung im Suchmuster übereinstimmt. Da die Ziffer ist 1, bezieht sich dies auf die erste Klammergruppierung. (In diesem Fall gibt es natürlich nur eine solche Gruppierung.)

Zusammenfassend bedeutet dieser Bearbeitungsbefehl, dass der in diesen Klammern übereinstimmende Text (der das letzte Zeichen der Zeile ist) verwendet wird, um den Text zu ersetzen, der durch den gesamten Suchregex (der die letzten beiden Zeichen der Zeile darstellt) übereinstimmt .

Der Nettoeffekt besteht darin, das vorletzte Zeichen aus jeder Zeile zu entfernen.

Genauer gesagt, sedwird jede Textzeile aus der Datei eingelesen, file.txtdie im aktuellen Arbeitsverzeichnis gefunden wurde. Für jede Zeile werden die letzten beiden Zeichen der Zeile durch das einzelne letzte Zeichen dieser Zeile ersetzt. und es wird jede geänderte Zeile auf ihre Standardausgabe gedruckt .

Platzhalter
quelle