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 Siesponge
. 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