Wie verwende ich einen Shell-Befehl, um nur die erste und die letzte Spalte in einer Textdatei anzuzeigen?

Ich benötige Hilfe, um herauszufinden, wie mit dem Befehl sed nur die erste und die letzte Spalte in einer Textdatei angezeigt werden. Folgendes habe ich bisher für Spalte 1:

cat logfile | sed "s/\|/ /"|awk "{print $1}" 

Mein schwacher Versuch, die letzte Spalte ebenfalls anzuzeigen, war:

cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}" 

Dabei werden jedoch die erste und die letzte Spalte verwendet und in einer Liste zusammengeführt. Gibt es eine Möglichkeit, die erste und die letzte Spalte mit den Befehlen sed und awk klar zu drucken?

Beispieleingabe:

foo|dog|cat|mouse|lion|ox|tiger|bar 

Kommentare

  • Bitte geben Sie einige Beispieleingaben an.

Antwort

Fast da. Stellen Sie einfach beide Spaltenreferenzen nebeneinander.

cat logfile | sed "s/|/ /" | awk "{print $1, $8}" 

Beachten Sie auch, dass Sie cat hier nicht benötigen

sed "s/|/ /" logfile | awk "{print $1, $8}" 

Beachten Sie auch, dass Sie awk mitteilen können, dass die Spaltentrennzeichen | anstelle von Leerzeichen, sodass Sie auch sed nicht benötigen.

awk -F "|" "{print $1, $8}" logfile 

Gemäß -Vorschlägen von Caleb , wenn Sie eine Lösung wünschen, die noch das letzte Feld ausgibt Auch wenn es nicht genau acht gibt, können Sie $NF verwenden.

awk -F "|" "{print $1, $NF}" logfile 

Auch wenn Sie das möchten Ausgabe, um die Trennzeichen | beizubehalten. Anstatt ein Leerzeichen zu verwenden, können Sie die Trennzeichen für das Ausgabefeld angeben. Leider ist es „etwas ungeschickter als nur die Verwendung des Flags -F, aber hier sind drei Ansätze.

  • Sie können die Eingabe zuweisen und Ausgabefeldtrennzeichen in awk selbst im BEGIN-Block.

    awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile 
  • Sie können diese Variablen zuweisen, wenn Sie awk über die Befehlszeile über das Flag -v aufrufen.

    awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile 
  • oder einfach:

    awk -F "|" "{print $1 "|" $8}" logfile 

Kommentare

  • Gute Arbeit, um herauszufinden, wie dieses Problem vereinfacht werden kann. Sie können einen Hinweis hinzufügen, wie | anstelle von Ausgabetrennzeichen verwendet wird Der Standardbereich für die Verkettung von Zeichenfolgen. Sie können auch erklären, dass $NF anstelle der harten Codierung $8 verwendet wird, um die letzte Spalte abzurufen.
  • danach, wie man die Datei aktualisiert?
  • @pankajprasad Schreiben Sie in eine neue Datei mit h > überschreiben Sie dann die alte oder verwenden Sie sponge. Dies ist jedoch wirklich eine neue Frage.
  • @Sparhawk funktioniert, aber das Reiben von Inhalten wird gelöscht. Wie gehe ich damit um?
  • @pankajprasad Sie müssen eine neue Frage stellen. Klicken Sie oben auf die große blaue Schaltfläche mit der Aufschrift “ Frage stellen „.

Antwort

Sie verwenden ohnehin awk:

awk "{ print $1, $NF }" file 

Kommentare

  • ‚ Sie müssen das Eingabefeldtrennzeichen nicht angeben (da dies in diesem Fall der Fall zu sein scheint) | eher dieses Leerzeichen) mit -F\| oder ähnlich sein? Was ist auch, wenn er dasselbe Trennzeichen für die Ausgabe verwenden möchte?
  • @Caleb Wahrscheinlich: Ich habe darauf gewartet, dass das OP bestätigt, wie genau die Eingabe aussieht, anstatt es zu versuchen Vermutung basierend auf den nicht funktionierenden Beispielen …
  • Beachten Sie, dass davon ausgegangen wird, dass die Eingabe mindestens 2 Felder enthält.
  • @St é phaneChazelas OP hat im Code klar angegeben, dass es immer acht Felder hat.
  • @ michaelb958 Ich denke “ klar “ übertreibt den Fall, nur ein wenig 🙂

Antwort

Ersetzen Sie einfach vom ersten zum letzten | mit einem | (oder Leerzeichen, wenn Sie es vorziehen):

sed "s/|.*|/|/" 

Beachten Sie, dass es zwar keine sed -Implementierung gibt, bei der | etwas Besonderes ist (solange erweitert regulär ist Ausdrücke werden nicht über -E oder in einigen Implementierungen), \| selbst ist in einigen wie GNU sed etwas Besonderes. Sie sollten also nicht | entkommen, wenn Sie beabsichtigen, dass es mit dem Zeichen | übereinstimmt.

Wenn das Ersetzen durch Leerzeichen erfolgt und die Eingabe möglicherweise bereits Zeilen mit nur einer | enthält, müssen Sie dies speziell als |.*| passt nicht zu diesen.Das könnte sein:

sed "s/|\(.*|\)\{0,1\}/ /" 

(dh der Teil .*| ist optional) Oder:

sed "s/|.*|/ /;s/|/ /" 

oder:

sed "s/\([^|]*\).*|/\1 /" 

Wenn Sie das erste und das achte Feld unabhängig von der Anzahl der Felder in möchten die Eingabe, dann ist es nur:

cut -d"|" -f1,8 

(all diese würden mit jedem POSIX-kompatiblen Dienstprogramm funktionieren, wenn die Eingabe vorausgesetzt wird bildet gültigen Text (insbesondere die sed funktionieren im Allgemeinen nicht, wenn die Eingabe Bytes oder Folgen von Bytes enthält, die im aktuellen Gebietsschema keine gültigen Zeichen bilden, wie zum Beispiel printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/" in einem UTF-8-Gebietsschema)).

Antwort

Wenn Sie sich ungeschickt und ohne Sed befinden, können Sie das erreichen Gleiches gilt für coreutils:

paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev) 

Kommentare

  • cut ist sauberer und kompakter als awk / sed, wenn Sie nur an der ersten Spalte interessiert sind oder wenn die Begrenzer fest sind (dh keine variable Anzahl von Leerzeichen).
  • Ziemlich elegant!

Antwort

Es scheint, als würden Sie versuchen, das erste und das letzte Textfeld abzurufen, die durch |.

Ich nahm an, dass Ihre Protokolldatei den folgenden Text enthält:

foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo 

Und Sie möchten Die Ausgabe lautet wie folgt:

foo bar bar foo 

Wenn ja, dann kommt hier der Befehl für Ihre „s

Through GNU sed,

sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file 

Beispiel:

$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar 

Kommentare

  • Die Spalten werden nicht durch eine Pipe | begrenzt aber sie sind in Spalten, ich bin daran interessiert, sed zu verwenden, aber nicht den Befehl awk, wie Sie es in Ihrem Befehl getan haben: sed -r ‚ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‚ Datei
  • “ Die Spalten sind nicht durch ein Rohr begrenzt | Sie befinden sich jedoch in Spalten „. Sie meinen, Spalten sind durch Leerzeichen getrennt?
  • Eine Beispieleingabe und eine Ausgabe wären besser.

Antwort

Sie sollten es wahrscheinlich mit sed tun – ich würde es trotzdem tun – aber nur weil noch niemand diesen geschrieben hat:

while IFS=\| read col1 cols do printf %10s%-s\\n "$col1 |" " ${cols##*|}" done <<\INPUT foo|dog|cat|mouse|lion|ox|tiger|bar INPUT 

AUSGABE

 foo | bar 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.