So löschen Sie die letzte Spalte einer Datei unter Linux

25

Ich möchte die letzte Spalte einer txt-Datei löschen, obwohl ich die Spaltennummer nicht kenne. Wie könnte ich das machen?

Beispiel:

Eingang:

1223 1234 1323 ... 2222 123
1233 1234 1233 ... 3444 125
0000 5553 3455 ... 2334 222

Und ich möchte, dass meine Ausgabe:

1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334
zara
quelle
Es gibt viele Möglichkeiten, dies zu tun. Bitte fügen Sie ein Beispiel und Ihre erwartete Ausgabe davon hinzu.
heemayl
@heemayl ok ich habe
zara
Danke ... sind die Spalten durch Tabulatoren oder Leerzeichen getrennt?
Heemayl
@heemayl Raum ist Deliminator
Zara

Antworten:

43

Mit awk:

awk 'NF{NF-=1};1' <in >out

oder:

awk 'NF{NF--};1' <in >out

oder:

awk 'NF{--NF};1' <in >out

Obwohl dies wie Voodoo aussieht, funktioniert es. Jeder dieser awk-Befehle besteht aus drei Teilen.

Das erste ist NF, was eine Voraussetzung für den zweiten Teil ist. NFist eine Variable, die die Anzahl der Felder in einer Zeile enthält. In AWK sind die Dinge wahr, wenn sie nicht 0 oder eine leere Zeichenfolge sind "". Daher NFgeschieht der zweite Teil (in dem dekrementiert wird) nur, wenn er NFnicht 0 ist.

Der zweite Teil (entweder NF-=1 NF--oder --NF) subtrahiert nur einen von der NFVariablen. Auf diese Weise wird verhindert, dass das letzte Feld gedruckt wird. Wenn Sie ein Feld ändern (in diesem Fall das letzte Feld entfernen), müssen Sie alle durch Leerzeichen getrennten Felder awkneu erstellen $0und verketten. $0enthielt nicht mehr das letzte Feld.

Der letzte Teil ist 1. Es ist nicht magisch, es wird nur als Ausdruck verwendet, der bedeutet true. Wenn ein awkAusdruck ohne zugeordnete Aktion als wahr ausgewertet wird, awklautet die Standardaktion print $0.

cuonglm
quelle
@ Joao: Ah, danke, vergessen --. Ein Hinweis, den Sie derzeit ;1für POSIX-konform benötigen .
Dienstag,
Mein anfänglicher Instinkt wäre, eine for-Schleife zu verwenden, aber das ist viel prägnanter und klüger.
Sergiy Kolodyazhnyy
5
Wenn Sie ein nicht standardmäßiges Trennzeichen verwenden, müssen Sie einige Änderungen vornehmen. Vorausgesetzt, ,Ihr Trennzeichen lautet:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
Mr. Llama
1
Die Auswirkung der NF-Dekrementierung ist undefiniertes Verhalten von POSIX - Sie erhalten unterschiedliche Ausgaben, je nachdem, welche awk Sie ausführen. Einige awks entfernen das letzte Feld wie gewünscht, andere tun gar nichts und andere melden möglicherweise einen Syntaxfehler oder ähnliches.
Ed Morton
16

Verwendung grepmit PCRE:

$ grep -Po '.*(?=\s+[^\s]+$)' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

GNU benutzen sed:

$ sed -r 's/(.*)\s+[^\s]+$/\1/' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334
heemayl
quelle
1
@ Ramin Sure .. Könnten Sie es bitte als eine neue Frage stellen (so funktioniert diese Seite) :)
Heemayl
@ramin Gibt es eine zeitliche Einschränkung oder eine Warnung?
Heemayl
es heißt, das kommt nicht in Frage!
Zara
@ramin Ok ... lass mich einen Admin kontaktieren, vielleicht können sie dir dabei helfen ... ob du irgendeine alte QA bezüglich deiner Frage überprüft hast? Es ist möglich, dass die Frage bereits gestellt und beantwortet wird.
Heemayl
3
Stellen Sie keine einfachen Fragen wie " Wie kann ich einen Dateinamen unter Linux umbenennen ? ". Benutze Google.
Christoffer Hammarström
11

Perl benutzen:

perl -lane '$,=" ";pop(@F);print(@F)' in

Mit rev+ cut:

rev in | cut -d ' ' -f 2- | rev
kos
quelle
5

Verwendung von GNU sed:

sed -r 's/\s+\S+$//' input.txt

Im Allgemeinen funktioniert dies mit dem BSD sed in OSX sowie mit GNU sed:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//' input.txt
Digitales Trauma
quelle
1

Wenn das Trennzeichen immer ein einzelnes Zeichen ist (zwei oder mehr aufeinanderfolgende Trennzeichen kennzeichnen leere Felder), können Sie headnur die erste Zeile aus Ihrer Eingabedatei auswählen, die Trennzeichen zählen ( nTrennzeichen bedeutet Anzahl der Felder n+1) und dann cutvom 1st-Feld aus drucken bis zum nvorletzten Feld, zB bei tabulatorgetrennter Eingabe:

n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l)
cut -f1-$n infile > outfile

oder zB mit einer csv datei:

n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l)
cut -d, -f1-$n infile > outfile

Ich werde später einige Benchmarks durchführen, wenn ich Zeit habe, aber mit großem Input denke ich, dass diese Lösung schneller sein sollte als andere Lösungen, die Regex verwenden, da diese minimale Verarbeitung in der ersten Zeile vornimmt, um die Nr. Zu erhalten. von Feldern und dann verwendet, cutdie für diesen Job optimiert ist.

don_crissti
quelle
1

Portabel können Sie eine der folgenden Optionen verwenden:

sed 's/[[:space:]]*[^[:space:]]*$//' file

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file
Ed Morton
quelle
0

Vim benutzen:

Datei in vim öffnen

vim <filename> 

Gehen Sie in die erste Zeile, nur für den Fall, dass sich der Cursor an einer anderen Stelle befindet.

gg

Erstellen Sie ein Makro mit dem Namen „q“ qq, die auf der Rückseite der aktuellen Zeile geht $, dann geht zurück auf den letzten Platz F(Hauptstadt F, gefolgt von wörtlichen SPACE) , dann löschen Sie von der aktuellen Position durch Zeilenende Dnach unten gehen in die nächste Zeile jund Stoppen Sie die Makroaufnahme mit q.

qq$F Djq

Jetzt können wir unser Makro mit @qfür jede Zeile wiederholen .
Wir können auch drücken @@, um das letzte Makro zu wiederholen oder noch einfacher:

99@q

um das Makro 99 Mal zu wiederholen.
Hinweis: Die Nummer muss nicht genau mit den Zeilen übereinstimmen.

cee
quelle
0

Bei Personen mit ähnlichen Problemen, jedoch mit unterschiedlichen Feldtrennzeichen awk, wird das Feldtrennzeichen durch diese Methode korrekt beibehalten:

$ cat file 
foo.bar.baz
baz.bar.foo
$ awk -F'.' 'sub(FS $NF,x)' file
foo.bar
baz.bar
htaccess
quelle