Wie drucke ich alle Spalten nach einer bestimmten Nummer mit awk?

88

Auf der Shell pfeife ich zu awk, wenn ich eine bestimmte Spalte benötige.

Dies druckt Spalte 9, zum Beispiel:

... | awk '{print $9}'

Wie kann ich awk anweisen, alle Spalten einschließlich und nach Spalte 9 zu drucken , nicht nur Spalte 9?

Laser
quelle

Antworten:

82
awk '{ s = ""; for (i = 9; i <= NF; i++) s = s $i " "; print s }'
Amadan
quelle
3
ein paar leichte Verfeinerungen:awk -v N=9 '{sep=""; for (i=N; i<=NF; i++) {printf("%s%s",sep,$i); sep=OFS}; printf("\n")}'
Glenn Jackman
Danke @glenn, das ist in der Tat etwas allgemeiner. Wie auch immer - ich würde auf jeden Fall zustimmen , es wäre besser zu nutzen cutoder perldafür. Verwenden Sie dies nur, wenn Sie wirklich darauf bestehen, es zu haben awk.
Amadan
1
@SiegeX: Es werden keine NUL-Bytes hinzugefügt, sondern der FS bleibt zwischen den einzelnen leeren Feldern erhalten.
Bis auf weiteres angehalten.
1
Die Eleganz finden Sie in der Antwort von @ Ascherer.
3
@veryhungrymike: Eleganz ist nett, aber ich würde lieber richtig sein. : p
Amadan
68

Wenn Sie eine Reihe von Feldern ausführen möchten, awkhaben Sie keine direkte Möglichkeit, dies zu tun. Ich würde cutstattdessen empfehlen :

cut -d' ' -f 9- ./infile

Bearbeiten

Leerzeichen-Feldbegrenzer hinzugefügt, da standardmäßig eine Registerkarte ist. Vielen Dank an Glenn für diesen Hinweis

SiegeX
quelle
15
Eine Sache beim Ausschneiden ist, dass es ein bestimmtes Trennzeichen verwendet (standardmäßig Registerkarte), wobei awk "Leerzeichen" verwendet. Beim Ausschneiden begrenzen 2 aufeinanderfolgende Registerkarten ein leeres Feld.
Glenn Jackman
1
Wie @glennjackman betonte, ist das Trennzeichen von awk "Leerzeichen" (auch ein beliebiger Betrag). Das Setzen des Schnitttrennzeichens auf ein einzelnes Leerzeichen würde also auch nicht zum Verhalten passen. Leider ist die Schleife die beste, die man machen kann, also sieht es so aus.
Poncha
Dieser funktioniert nicht richtig. Versuchen Sie den Befehl find . | xargs ls -l | cut -d' ' -f 9-. Aus irgendeinem Grund werden auch doppelte Leerzeichen gezählt. Beispiel: lrwxrwxrwx 1 me me 21 Dec 12 00:00 ./file_a lrwxrwxrwx 1 me me 64 Dec 6 00:06 ./file_bführt zu./file_a 00:06 ./file_b
Marco Pashkov
@MarcoPashkov Bitte erläutern Sie dies. Dieser funktioniert nicht richtig , insbesondere wenn Sie genau den gleichen Code in Ihrer Pipeline verwenden. Übrigens sollten Sie niemals versuchen, die Ausgabe von ls
SiegeX am
Schnitt macht hier nicht den Job. Wenn Ihre Eingabe beispielsweise "foo bar" (einzelnes Leerzeichen) für eine Zeile und "foo ___ bar" (dh mehrere Leerzeichen, aber SO ist zu intelligent, um sie anzuzeigen) für eine andere Zeile lautet, werden sie beim Ausschneiden anders verarbeitet.
UKMonkey
53
awk '{print substr($0, index($0,$9))}'

Bearbeiten : Beachten Sie, dass dies nicht funktioniert, wenn ein Feld vor dem neunten den gleichen Wert wie das neunte enthält.

Ascherer
quelle
2
Dieser ist brillant!
10
@veryhungrymike: ... und funktioniert nicht, wenn ein Feld vor dem neunten den gleichen Wert wie das neunte enthält.
Amadan
6
Wahrscheinlich wegen des klassischen Satzes "Hoffentlich hat Ihre Datei dieses Problem nicht". Es ist ein absolutes No-No in der S / W-Technik zu sagen: "Wir werden keine Zeit damit verschwenden, Fehler zu überprüfen, um beispielsweise negative Werte einzugeben, denn 'wir hoffen, dass der Benutzer intelligent genug ist, um sie nicht auszuprobieren." Absturz unseres Werkzeugs '". HAHAHA! Ich liebe es immer das zu hören! (I wie ein guter Sinn für Humor) Nun, wie Idioten tun exist, dann ist es die Pflicht der Entwickler seine Sachen zu machen idiotensicher ! Anstatt "auf das Gute im Menschen zu hoffen". Das ist eher eine Einstellung, die von Philosophen erwartet wird, nicht von s / w-Ingenieuren ... LOL
Syntaxfehler
3
Ich habe nicht gesagt, nicht nach Fehlern zu suchen, aber wenn Sie wissen, dass Sie nicht auf das Problem stoßen werden, ist diese Lösung in Ordnung, wie ich bereits sagte. Aber danke für die unnötige Ablehnung @syntaxerror. Diese Lösung funktioniert für einige, wie die (derzeit) 19 Upvotes zeigen, aber wenn dies nicht der Fall ist, verwenden Sie sie nicht für Ihre Lösung. Es gibt viele Möglichkeiten, das Problem des OP zu lösen.
Ascherer
1
Wenn Sie awk in Ihrer täglichen Arbeit in der Befehlszeile verwenden, ist dies definitiv die gewünschte Lösung. Ist es nicht offensichtlich? Fehlerprüfung usw. spielt in diesem Fall keine Rolle, da Sie sie eingeben und diese Art von Dingen abfangen können, bevor Sie die Eingabetaste drücken (ich persönlich denke nicht, dass awk für irgendetwas anderes verwendet werden sollte, deshalb wir Ich habe Perl, Python, Tcl und über 100 andere, bessere, schnellere, weniger nervige Skriptsprachen!) Natürlich gebe ich meinen Kollegen von Softwareentwicklern zu viel Anerkennung und sie müssen wirklich Fehler überprüfen, selbst wenn sie etwas eingeben on the fly (??)
Osirisgothra
11
sed -re 's,\s+, ,g' | cut -d ' ' -f 9-

Ersetzen Sie anstelle von Leerzeichen mit variabler Breite alle Leerzeichen als einzelne Leerzeichen. Dann verwenden Sie einfach cutmit den Feldern von Interesse.

Es verwendet kein awk, ist also nicht deutsch, schien aber angesichts der anderen Antworten / Kommentare angemessen.

Ein Narr
quelle
1
Bitte machen Sie Ihre Antwort gründlicher, andernfalls posten Sie dies als Kommentar zur Frage.
Alper Turan
Dies ist ideal für den ps faux | Einsatz. Haben Sie niemals Angst, das Tool XYZ zuzulassen, das nicht am besten geeignet ist.
Kevinf
10

Im Allgemeinen ersetzt Perl awk / sed / grep et. al. und ist viel tragbarer (und einfach nur ein besseres Taschenmesser).

perl -lane 'print "@F[8..$#F]"'

Timtowtdi gilt natürlich.

Bobbogo
quelle
Sie müssen die Befehlszeilenoption hinzufügen -loder \nder print-Anweisung hinzufügen .
Glenn Jackman
@ Glenn Jackman: Möglicherweise. Nicht erforderlich, wenn ein Teil einer anderen Nachricht oder eine Variable usw. zugewiesen ist. Was "besser" betrifft, sieht Perl im Kleinen sicherlich besser aus. Kann zugegebenermaßen im Großen sehr unordentlich aussehen.
Bobbogo
Versteh mich nicht falsch, ich mag Perl. Ich liebe awk für das, was es ist.
Glenn Jackman
Mein eingebettetes Gerät kommt nicht mit Perl, aber es hat awk.
Sepero
Downvoting, weil die Frage lautete, wie man das in awk macht, nicht in perl, ruby, java, python, bash.
Tom Harrison
3
awk -v m="\x01" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

Dies zerhackt, was vor dem angegebenen Feld nr., N steht, und druckt den gesamten Rest der Zeile, einschließlich Feld nr.N, und behält den ursprünglichen Abstand bei (es wird nicht neu formatiert). Es spielt keine Rolle, ob die Zeichenfolge des Feldes auch an einer anderen Stelle in der Zeile erscheint, was das Problem mit Ascherers Antwort ist.

Definieren Sie eine Funktion:

fromField () { 
awk -v m="\x01" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

Und benutze es so:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost   

Die Ausgabe behält alles bei, einschließlich nachfolgender Leerzeichen. Für N = 0 wird die gesamte Zeile unverändert und für n> NF die leere Zeichenfolge zurückgegeben

Robert Vila
quelle
Das ist eine gute Idee. Auf einem aktuellen Mac mit typischem Gawk funktioniert es nicht ganz, da $ 0 zusammenbricht. Die Lösung besteht darin, als ersten Schritt eine Variable auf $ 0 zu setzen, z. B.: '{S = $ 0; ... drucke substr (s, index (s, m) +1}
joelparkerhenderson
1

Hier ist ein Beispiel für die ls -lAusgabe:

-rwxr-----@ 1 ricky.john  1493847943   5610048 Apr 16 14:09 00-Welcome.mp4
-rwxr-----@ 1 ricky.john  1493847943  27862521 Apr 16 14:09 01-Hello World.mp4
-rwxr-----@ 1 ricky.john  1493847943  21262056 Apr 16 14:09 02-Typical Go Directory Structure.mp4
-rwxr-----@ 1 ricky.john  1493847943  10627144 Apr 16 14:09 03-Where to Get Help.mp4

Meine Lösung, um irgendetwas zu drucken, $9istawk '{print substr($0, 61, 50)}'

Rickydj
quelle
0
ruby -lane 'print $F[3..-1].join(" ")' file
kurumi
quelle
0

So zeigen Sie die ersten 3 Felder an und drucken die verbleibenden Felder aus:

awk '{s = ""; for (i=4; i<= NF; i++) s= s $i : "; print $1 $2 $3 s}' filename

Dabei sind $ 1 $ 2 $ 3 die ersten 3 Felder.

Raymond C Borges Hink
quelle
0
function print_fields(field_num1, field_num2){
    input_line = $0

    j = 1;
    for (i=field_num1; i <= field_num2; i++){
        $(j++) = $(i);

    }
    NF = field_num2 - field_num1 + 1;
    print $0

    $0 = input_line
}
msol01
quelle
0

Verwenden Sie cut anstelle von awk und überwinden Sie Probleme mit dem Befehl -c cut cut, um herauszufinden, bei welcher Spalte Sie beginnen sollen.

Hier sage ich, gib mir alle bis auf die ersten 49 Zeichen der Ausgabe.

 ls -l /some/path/*/* | cut -c 50-

Das /*/*/ Befehl am Ende des Befehls ls zeigt an, was sich auch in Unterverzeichnissen befindet.

Sie können auch bestimmte Zeichenbereiche herausziehen (aus der Manpage zum Ausschneiden). Zeigen Sie beispielsweise die Namen und Anmeldezeiten der aktuell angemeldeten Benutzer an:

       who | cut -c 1-16,26-38
Joe
quelle