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

30

Ich brauche Hilfe, um herauszufinden, wie der Befehl sed verwendet wird, um nur die erste und die letzte Spalte in einer Textdatei anzuzeigen. Folgendes habe ich bisher für Spalte 1:

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

Mein schwacher Versuch, die letzte Spalte auch zu zeigen, war:

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

Dabei werden jedoch die erste und die letzte Spalte in einer Liste zusammengefasst. Gibt es eine Möglichkeit, die erste und die letzte Spalte mit sed- und awk-Befehlen deutlich auszudrucken?

Beispieleingabe:

foo|dog|cat|mouse|lion|ox|tiger|bar
user70573
quelle
5
Bitte geben Sie einige Beispiele ein.
Jasonwryan

Antworten:

51

Fast dort. Stellen Sie einfach beide Spaltenverweise nebeneinander.

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

Beachten Sie auch, dass Sie cathier nicht brauchen .

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

Beachten Sie auch, awkdass die Spaltentrennzeichen |keine Leerzeichen sind, sodass Sie auch keine benötigen sed.

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

Nach den Vorschlägen von Caleb können Sie eine Lösung verwenden, die auch dann das letzte Feld ausgibt, wenn es nicht genau acht gibt $NF.

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

Wenn Sie möchten, dass die Ausgabe die |Trennzeichen beibehält, anstatt ein Leerzeichen zu verwenden, können Sie auch die Trennzeichen für die Ausgabefelder angeben. Leider ist es etwas umständlicher als nur die -FFlagge zu benutzen , aber hier sind drei Ansätze.

  • Sie können die Trennzeichen für Ein- und Ausgabefelder awkim BEGIN-Block selbst zuweisen .

    awk 'BEGIN {FS = OFS = "|"} {print $1, $8}' logfile
  • Sie können diese Variablen beim Aufruf awkvon der Kommandozeile über das -vFlag zuweisen .

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

    awk -F '|' '{print $1 "|" $8}' logfile
Sparhawk
quelle
4
Gut aufgeschlüsselt, wie dieses Problem vereinfacht werden kann. Möglicherweise fügen Sie |anstelle des Standardbereichs für die Zeichenfolgenverkettung einen Hinweis zur Verwendung als Ausgabetrennzeichen hinzu. Sie könnten auch erklären, dass Sie $NFanstelle der festen Codierung verwenden $8, um die letzte Spalte zu erhalten.
Caleb
12

Ersetzen Sie einfach vom ersten bis zum letzten |durch ein |(oder ein Leerzeichen, wenn Sie es vorziehen):

sed 's/|.*|/|/'

Beachten Sie, dass es zwar keine spezielle sedImplementierung |gibt (solange über oder in einigen Implementierungen keine erweiterten regulären Ausdrücke aktiviert sind ), in einigen Fällen jedoch eine besondere Implementierung vorliegt, z . B. in GNU . Also solltest du nicht-E-r\|sed entkommen, |wenn Sie beabsichtigen, dass es mit dem |Charakter übereinstimmt .

Wenn Sie durch Leerzeichen ersetzen und die Eingabe möglicherweise bereits Zeilen mit nur einem enthält |, müssen Sie dies als besonders behandeln|.*| es bei diesen nicht übereinstimmt. Das könnte sein:

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

(das ist machen die .*| Teil 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 der Eingabe wünschen, dann ist es nur:

cut -d'|' -f1,8


(Alle funktionieren mit jedem POSIX - kompatiblen Dienstprogramm, vorausgesetzt, die Eingabe bildet gültigen Text. (Insbesondere sedfunktionieren diese 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 ein UTF-8-Gebietsschema)).

Stéphane Chazelas
quelle
11

Sie verwenden awksowieso:

awk '{ print $1, $NF }' file
jasonwryan
quelle
2
Müssten Sie nicht das Eingabefeld-Trennzeichen (da es in diesem Fall |eher das Leerzeichen zu sein scheint ) mit -F\|oder ähnlich angeben ? Was ist auch, wenn er das gleiche Trennzeichen für die Ausgabe verwenden möchte?
Caleb
@Caleb Wahrscheinlich: Ich habe darauf gewartet, dass das OP bestätigt, wie die Eingabe genau aussieht , anstatt anhand der nicht funktionierenden Beispiele zu raten ...
jasonwryan
1
Beachten Sie, dass die Eingabe mindestens 2 Felder enthält.
Stéphane Chazelas
@ StéphaneChazelas OP hat im Code eindeutig angegeben, dass es immer acht Felder hat.
michaelb958 - Wiedereinsetzung von Monica am
3
@ michaelb958 Ich denke, "klar" ist der Fall nur ein wenig übertrieben :)
jasonwryan
4

Wenn Sie sich ohne Probleme und ohne Sedimente fühlen, können Sie dasselbe mit coreutils erreichen:

paste <(           cut -d'|' -f1  file) \ 
      <(rev file | cut -d'|' -f1 | rev)
Thor
quelle
cutist sauberer und kompakter als awk / sed, wenn Sie nur an der ersten Spalte interessiert sind oder wenn die Begrenzungslinien festgelegt sind (dh keine variable Anzahl von Leerzeichen).
Sridhar Sarnobat
2

Es sieht so aus, als ob Sie versuchen, das erste und das letzte Textfeld abzurufen, die durch begrenzt sind |.

Ich bin davon ausgegangen, 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 wie folgt:

foo bar
bar foo

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

Durch 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
Avinash Raj
quelle
Die Spalten werden nicht durch eine Pipe | begrenzt aber sie sind in Spalten, ich bin daran interessiert, sed zu verwenden, aber nicht den awk-Befehl zu verwenden, wie Sie es in Ihrem Befehl getan haben: sed -r 's ~ ^ ([^ |] *). * \ | (. *) $ ~ \ 1 \ 2 ~ 'file
user70573
Msgstr "Die Spalten werden nicht durch eine Pipe | begrenzt, sondern befinden sich in Spalten", meinst du, Spalten werden durch Leerzeichen getrennt?
Avinash Raj
Ein Sample Input und ein Output wären besser.
Avinash Raj
1

Sie sollten es wahrscheinlich mit sed- ich würde es sowieso tun - aber nur weil noch niemand dieses 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
mikeserv
quelle