Wie kann ich das 5. Wort jeder Zeile in einer Datei löschen?

13

Ich möchte das 5. Wort jeder Zeile in einer Datei löschen.

Der aktuelle Inhalt der Datei:

File is not updated or and will be removed  
System will shut down f within 10 seconds  
Please save your work 55 or copy to other location  
Kindly cooperate with us D  

Erwartete Ausgabe:

File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
pmaipmui
quelle

Antworten:

31

Wie wäre es mit cut:

$ cut -d' ' -f1-4,6- file.txt 
File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
  • -d' ' Legt das Trennzeichen als Leerzeichen fest

  • -f1-4,6- Wählt das erste bis vierte Feld (Wort) aus, lässt das fünfte und druckt dann vom sechsten bis zum restlichen Feld weiter.

heemayl
quelle
11

Eine Lösung mit cut:

cut -d ' ' -f1-4 -f6- FILE
fd0
quelle
Multiple -fwird in meinem cut(GNU) zumindest nicht unterstützt ..
heemayl
Wird im BSD-Schnitt unterstützt, aber ich finde deine Antwort besser als meine.
fd0
1
Wenn es GNU Schnitt, erhalten Sie die --complementFlagge , um die Dinge zu vereinfachen: cut --complement -d ' ' -f5. Denken Sie daran, die Ausgabe in eine neue Datei umzuleiten und dann mvüber die Originaldatei zu verschieben.
Toby Speight,
6

awk: entferne das fünfte feld

awk '{for (i=5; i<NF; i++) $i = $(i+1); NF--};1' file

Wenn Sie die Datei direkt speichern möchten: /programming//q/16529716/7552

Sie können den Inhalt des 5. Feldes einfach löschen, es bleiben jedoch 2 aufeinanderfolgende Trennzeichen für die Ausgabefelder:

awk '{$5 = ""};1' file
Glenn Jackman
quelle
Die Einschränkung hierbei ist, dass das Ändern eines Feldwerts in awk den Nebeneffekt hat, dass das gesamte "$ 0" mit nur 1 Trennzeichen zwischen den einzelnen Feldern neu geschrieben wird. sollte berücksichtigt werden, wenn Sie eine Ausrichtung beibehalten möchten (es sei denn, gnu awk hat eine Option, um dies zu vermeiden? reguläre awk / nawk berechnet $ 0 neu)
Olivier Dulac
In beiden Fällen formatieren Sie die Zeile mit einem einzelnen Trennzeichen neu. Befindet sich in einem Trennzeichen 2 Leerzeichen oder ein Leerzeichen + Tabulator, ist das Ergebnis ein einzelnes Leerzeichen. Dies ist hoffentlich für den größten Teil des Textes in Ordnung.
NeronLeVelu
4

Mit POSIX sed:

sed -e 's/[^[:alnum:]_][[:alnum:]_][[:alnum:]_]*//4' <file
cuonglm
quelle
warum beschränken Sie die Klasse auf: alnum: und _ nichts anderes als :blank:oder :space:?
NeronLeVelu
@NeronLeVelu: Das kommt darauf an, wie du definierst, was ein Wort ausmacht.
Donnerstag,
@mikeserv; Schöner Fang! Ich habe meine Antwort aktualisiert.
Cuonglm
Wofür ist die \(Erfassungsgruppe \)?
mikeserv
@mikeserv: Mein Tippfehler, ich habe gerade einige Möglichkeiten ausprobiert, um das Trennzeichen beizubehalten.
Dienstag,
2

glenn bot eine lösung an, die äquivalent zu ist

awk '{$ 5 = ""; print} ' file

Wie er und andere darauf hingewiesen haben, ist dies

  1. Entfernt führende und nachfolgende Leerzeichen aus jeder Zeile,
  2. komprimiert jeden Whitespace-String (Leerzeichen und / oder Tabulatoren) in ein einzelnes Leerzeichen
  3. Lässt zwei Leerzeichen zwischen dem vierten und sechs Wörtern.

Ein Hack, um das dritte Problem zu beheben, ist

awk '{$ 5 = ""; print} ' file | sed 's / / /'

Dadurch verbleiben am Ende einer Zeile, in der fünf oder weniger Wörter eingegeben wurden, noch ein oder mehrere Leerzeichen. Wenn Sie ein Wort identifizieren können, das in der Eingabe niemals vorkommt,

awk '{$ 5 = "Einhorn"; print} ' file | sed's / * unicorn // '

wird auch damit umgehen (aber es bleibt immer noch Probleme 1 und 2).

Scott
quelle
2
 sed 's/^\(\([[:blank:]]*[^[:blank:]]\{1,\}\)\{4\}\)[[:blank:]]*[^[:blank:]]*/\1/' YourFile > Output.txt
  • posix sed basierend auf Leerzeichen / Tabulatortrennzeichen (Metaklasse [: blank:]])
  • Lassen Sie nach dem 5. Wort das folgende Leerzeichen, aber entfernen Sie das vorhergehende

Eine robustere (sed nehmen Sie das längste mögliche Muster und Muster mit *könnte Trennung oder Wort in der ersten Version verfehlen), aber eine etwas längere Version

sed 's/^\([[:blank:]]*\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{4\}\[^[:blank:]]\{1,\}/\1/' YourFile > Output.txt
NeronLeVelu
quelle
1
sed 's/[^[:blank:]]*//5'
mikeserv
@mikeserv, dadurch bleiben beide umgebenden Trennzeichen erhalten, sed 's/[[:blank:]*[^[:blank:]]*//5'ist besser. Sehr guter Punkt. Ich vermutete, dass sed jedes einzelne Zeichen als Einheit
nimmt
sed 's/[[:blank:]][^[:blank:]]*//4'entfernt das 5. Feld vollständig.
mikeserv
@ MikeServ Angenommen, es gibt keinen Startplatz in der Zeile (wie im Beispiel)
NeronLeVelu
In diesem Fall, ja, ich denke du hast recht. Normalerweise wäre so etwas ein Nullfeld und das Verhalten wäre korrekt. In diesem Fall sollten Sie tun , als @cuonglm Sie ein Wort jedes Mal wie Referenz tat und gewährleisten sed 's/[[:blank:]][^[:blank:]][^[:blank:]]*//4', oder, w / GNU / BSD / toybox seds: sed -E 's/[[:blank:]][^[:blank:]]+//4'.
MikeServ
1

Perl.

perl -ne 'print $_ =~ /^(\w+ +\w+ +\w+ +\w+ +)\w+ (.*)/,"\n"' file
Steve
quelle
1

Eine andere Möglichkeit, vorausgesetzt, GNU-Cut:

cut -d' ' -f5 --complement file.txt
Digitales Trauma
quelle
-1

Verwenden von Perl> 5.10 (und erfolgreiches Ausgeben aller Zeilen: 0)): -

perl -nE '/^((\w+ +){4})\w+ *(.*)/; say $1.$3' file
Medlock Perlman
quelle