Drucken Sie alle bis auf die ersten drei Spalten


112

Zu umständlich:

awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things

43
Gibt es einen Grund, den Sie nicht einfach verwenden können cut -f3-?
Cascabel

1
@hhh schön .. Ich mag die Idee einer zusammenfassenden Antwort.
Chris Seymour

2
@Jefromi - weil es Zeilenpufferungsprobleme mit cut gibt, die awk nicht hat: stackoverflow.com/questions/14360640/…
sdaau


@Jefromi - hat auch cutkeine regulären Ausdrücke vor {}Aktionen, und dann ist es viel dümmer mit Feldtrennzeichen (variable Anzahl von Leerzeichen?), Und Sie müssen sie manuell angeben. Ich denke, das OP wollte von einem shift NBefehl hören, der nicht existiert. Das nächste ist $1="";$2="";(...);print}, aber in meinem Fall bleiben einige führende Leerzeichen (wahrscheinlich Trennzeichen).
Tomasz Gandor

Antworten:


50

Eine Lösung, die keine zusätzlichen führenden oder nachfolgenden Leerzeichen hinzufügt :

awk '{ for(i=4; i<NF; i++) printf "%s",$i OFS; if(NF) printf "%s",$NF; printf ORS}'

### Example ###
$ echo '1 2 3 4 5 6 7' |
  awk '{for(i=4;i<NF;i++)printf"%s",$i OFS;if(NF)printf"%s",$NF;printf ORS}' |
  tr ' ' '-'
4-5-6-7

Sudo_O schlägt eine elegante Verbesserung mit dem ternären Operator vorNF?ORS:OFS

$ echo '1 2 3 4 5 6 7' |
  awk '{ for(i=4; i<=NF; i++) printf "%s",$i (i==NF?ORS:OFS) }' |
  tr ' ' '-'
4-5-6-7

EdMorton bietet eine Lösung, bei der die ursprünglichen Leerzeichen zwischen den Feldern erhalten bleiben :

$ echo '1   2 3 4   5    6 7' |
  awk '{ sub(/([^ ]+ +){3}/,"") }1' |
  tr ' ' '-'
4---5----6-7

BinaryZebra bietet auch zwei fantastische Lösungen:
(Diese Lösungen bewahren sogar nachgestellte Leerzeichen von der ursprünglichen Zeichenfolge)

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ for ( i=1; i<=n; i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 ' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

Die von larsr in den Kommentaren angegebene Lösung ist fast richtig:

$ echo '1 2 3 4 5 6 7' | 
  awk '{for (i=3;i<=NF;i++) $(i-2)=$i; NF=NF-2; print $0}' | tr  ' ' '-'
3-4-5-6-7

Dies ist die feste und parametrisierte Version der Larsr- Lösung:

$ echo '1 2 3 4 5 6 7' | 
  awk '{for(i=n;i<=NF;i++)$(i-(n-1))=$i;NF=NF-(n-1);print $0}' n=4 | tr ' ' '-'
4-5-6-7

Alle anderen Antworten vor September 2013 sind nett, aber fügen Sie zusätzliche Leerzeichen hinzu:


Die Antwort von EdMorton hat bei mir nicht funktioniert (Bash 4.1.2 (1) -Release, GNU Awk 3.1.7 oder Bash 3.2.25 (1) -Release, GNU Awk 3.1.5), aber hier einen anderen Weg gefunden:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch

1
@elysch nein, das wird im Allgemeinen nicht funktionieren, es scheint nur bei bestimmten Eingabewerten zu funktionieren. Siehe den Kommentar, den ich unter Ihrem Kommentar unter meiner Antwort hinzugefügt habe.
Ed Morton

1
Hallo @fedorqui. Meine Antwort ist die erste. In meiner ursprünglichen Antwort habe ich erklärt, warum die andere Antwort nicht korrekt war (zusätzliches führendes oder nachfolgendes Leerzeichen). Einige Leute haben Verbesserungen in Kommentaren vorgeschlagen. Wir haben das OP gebeten, eine korrektere Antwort zu wählen, und er / sie hat meine ausgewählt. Nachdem einige andere Mitwirkende meine Antwort bearbeitet haben, um auf diese Antwort zu verweisen (siehe Verlauf). Ist es dir klar? Was raten Sie mir, um die Verständlichkeit meiner Antwort zu verbessern? Prost ;-)
Olibre

1
Sie haben absolut Recht und mein Missverständnis tut mir sehr leid. Ich habe die Antwort schnell gelesen und Ihre ursprüngliche Antwort nicht bemerkt (ja, ich habe zu schnell gelesen). +1 für die Antwort selbst mit dem netten Trick, um zu NF-1 zu gelangen und dann das letzte Element zu drucken, um das zusätzliche Leerzeichen zu vermeiden. Und nochmal Entschuldigung! (wird meinen Kommentar in ungefähr einem Tag entfernen, um Missverständnisse von zukünftigen Lesern zu vermeiden).
Fedorqui 'SO hör auf zu schaden'

1
Ich würde eine Art von Überschriften verwenden: <Ihre Antwort> und dann eine horizontale Regel, gefolgt von einem großen Titel "Vergleich der anderen Antworten". Andernfalls verschieben Sie diesen Vergleich auf eine andere Antwort, da die Leute anscheinend eher kurze Antworten in einer "gimme my code"
-Vision

75
awk '{for(i=1;i<4;i++) $i="";print}' file

4
Dies würde die Führung verlassen, OFSda Sie sich nicht mit dem NFführenden Platz in den Datensätzen befassen .
Chris Seymour

70

Verwenden Sie Schnitt

$ cut -f4-13 file

oder wenn Sie auf awk bestehen und $ 13 das letzte Feld ist

$ awk '{$1=$2=$3="";print}' file

sonst

$ awk '{for(i=4;i<=13;i++)printf "%s ",$i;printf "\n"}' file

14
wahrscheinlich besser "NF" als "13" im letzten Beispiel zu verwenden.
Glenn Jackman

2
2 Szenario, über das OP entscheiden muss. Wenn 13 das letzte Feld ist, ist die Verwendung von NF in Ordnung. Wenn nicht, ist die Verwendung von 13 angemessen.
Ghostdog74

3
2. muss 3 Kopien von OFS ab dem Beginn von $ 0 löschen. 3. wäre besser mit printf "%s ",$i, da man nicht weiß ob ob oder ähnliches $ienthalten könnte %s. Aber das würde am Ende einen zusätzlichen Platz drucken.
Dubiousjim

38

Versuche dies:

awk '{ $1=""; $2=""; $3=""; print $0 }'

1
Das ist schön, weil es so dynamisch ist. Sie können am Ende Spalten hinzufügen und Ihre Skripte nicht neu schreiben.
MinceMan

1
Dies zeigt das genaue Problem, mit dem sich die Frage befasst. Machen Sie genau das Gegenteil. Was ist mit dem Drucken aus dem 100. Feld? Beachten Sie, dass Sie sich nicht damit befassen NFund die Führung verlassen OFS.
Chris Seymour

24

Der richtige Weg, dies zu tun, ist ein RE-Intervall, da Sie einfach angeben können, wie viele Felder übersprungen werden sollen, und den Abstand zwischen den Feldern für die verbleibenden Felder beibehalten.

Die ersten drei Felder zu überspringen, ohne den Abstand zwischen den verbleibenden Feldern zu beeinflussen, ist angesichts des Eingabeformats, das wir in dieser Frage zu diskutieren scheinen, einfach:

$ echo '1   2 3 4   5    6' |
awk '{sub(/([^ ]+ +){3}/,"")}1'
4   5    6

Wenn Sie führende Leerzeichen und nicht leere Leerzeichen aufnehmen möchten, aber wieder mit dem Standard-FS, dann ist es:

$ echo '  1   2 3 4   5    6' |
awk '{sub(/[[:space:]]*([^[:space:]]+[[:space:]]+){3}/,"")}1'
4   5    6

Wenn Sie einen FS haben, der ein RE ist, den Sie in einem Zeichensatz nicht negieren können, können Sie ihn zuerst in ein einzelnes Zeichen konvertieren (RS ist ideal, wenn es sich um ein einzelnes Zeichen handelt, da ein RS NICHT in einem Feld angezeigt werden kann, andernfalls SUBSEP in Betracht ziehen). Wenden Sie dann die RE-Intervall-Subsitution an und konvertieren Sie sie in das OFS. zB wenn Ketten von "." die Felder trennten:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,RS);sub("([^"RS"]+["RS"]+){3}","");gsub(RS,OFS)}1'
4 5 6

Wenn OFS ein einzelnes Zeichen ist UND es nicht in den Eingabefeldern angezeigt werden kann, können Sie dies natürlich reduzieren auf:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,OFS); sub("([^"OFS"]+["OFS"]+){3}","")}1'
4 5 6

Dann haben Sie das gleiche Problem wie bei allen schleifenbasierten Lösungen, die die Felder neu zuweisen - die FSs werden in OFSs konvertiert. Wenn dies ein Problem ist, müssen Sie sich die patsplit () - Funktion von GNU awks ansehen.


Hat bei mir nicht funktioniert (Bash 4.1.2 (1) -Release, GNU Awk 3.1.7 oder Bash 3.2.25 (1) -Release, GNU Awk 3.1.5), aber hier einen anderen Weg gefunden:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
Elysch

2
Nein, das schlägt fehl, wenn $ 1 oder $ 2 die Zeichenfolge enthalten, auf die $ 3 gesetzt ist. Versuchen Sie , zum Beispiel , echo ' That is a test' | awk '{print substr($0, index($0,$3))}'und Sie werden feststellen , dass die , adie $ 3 entspricht dem ist ainnerhalb That1 in $. In einer sehr alten Version von gawk wie Sie müssen Sie RE-Intervalle mit dem Flag aktivieren --re-interval.
Ed Morton

2
Du hast recht, habe es nicht bemerkt. Übrigens, schätzen Sie Ihren Kommentar wirklich. Viele Male wollten Sie einen regulären Ausdruck mit "{}" verwenden, um die Anzahl der Elemente anzugeben, und sahen im Mann nie "--re-interval". +1 für dich.
Elysch

1
1ist eine echte Bedingung und ruft daher die Standard-awk-Aktion zum Drucken des aktuellen Datensatzes auf.
Ed Morton

1
idk wie kanonisch es ist, aber ich habe jetzt eine Antwort hinzugefügt.
Ed Morton

10

Nahezu alle Antworten fügen derzeit entweder führende Leerzeichen, nachfolgende Leerzeichen oder ein anderes Trennzeichen hinzu. Aus dem vierten Feld auszuwählen, in dem das Trennzeichen ein Leerzeichen und das Ausgabetrennzeichen ein einzelnes Leerzeichen ist, awkwäre:

awk '{for(i=4;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' file

So parametrisieren Sie das Startfeld:

awk '{for(i=n;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' n=4 file

Und auch das Endfeld:

awk '{for(i=n;i<=m=(m>NF?NF:m);i++)printf "%s",$i (i==m?ORS:OFS)}' n=4 m=10 file

6
awk '{$1=$2=$3="";$0=$0;$1=$1}1'

Eingang

1 2 3 4 5 6 7

Ausgabe

4 5 6 7

4
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) print $i }'

3
Oder um sie in dieselbe Zeile zu bringen, weisen Sie $ 3 bis $ 1 usw. zu und ändern Sie dann NF in die richtige Anzahl von Feldern. echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
Larsr

Hallo @larsr. Ihre vorgeschlagene Befehlszeile ist die einzige richtige Antwort. Alle anderen Antworten fügen zusätzliche Leerzeichen hinzu (führende oder nachfolgende). Bitte
poste

1
Hallo @sudo_O, ich habe mit @larsr über die Befehlszeile gesprochen, die er in seinem Kommentar vorgeschlagen hat. Ich verbrachte ungefähr fünf Minuten, bevor ich den Quiproco herausfand (Missverständnis). Ich bin damit einverstanden, dass die @ Veterin-Antwort neue Zeilen ( ORS) zwischen Felder einfügt . Bravo für Ihre Initiative (Ich mag Ihre Antwort). Cheers
Olibre

3

Eine andere Möglichkeit, die Verwendung der print-Anweisung zu vermeiden:

 $ awk '{$1=$2=$3=""}sub("^"FS"*","")' file

In awk, wenn eine Bedingung erfüllt ist, ist print die Standardaktion.


Dies hat alle Probleme @lhf Antwort hat .. es ist nur kürzer.
Chris Seymour

Sehr gute Idee;) Besser als meine Antwort! (Ich habe Ihre Antwort bereits letztes Jahr
positiv bewertet.

Es sollte sein: awk '{$1=$2=$3=""}sub("^"OFS"+","")' fileebenso wie das OFS, was nach dem Ändern des Inhalts von $ 1, $ 2 und $ 3 übrig bleibt.

3

Ich kann nicht glauben, dass niemand eine einfache Muschel angeboten hat:

while read -r a b c d; do echo "$d"; done < file

+1 für die ähnliche Lösung ... Dies kann jedoch zu Leistungsproblemen führen, wenn filees groß ist (> 10-30 KB). Bei großen Dateien awkbietet die Lösung eine bessere Leistung.
Richtig

3

Die Optionen 1 bis 3 haben Probleme mit mehreren Leerzeichen (sind jedoch einfach). Aus diesem Grund sollten die Optionen 4 und 5 entwickelt werden, mit denen mehrere Leerzeichen problemlos verarbeitet werden können. Wenn die Optionen 4 oder 5 mit n=0beiden verwendet werden, bleiben natürlich alle führenden Leerzeichen erhalten, da n=0keine Aufteilung erfolgt.

Option 1

Eine einfache Schnittlösung (funktioniert mit einzelnen Trennzeichen):

$ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4-
4 5 6 7 8

Option 2

Das Erzwingen einer awk-Neuberechnung löst manchmal das Problem (funktioniert mit einigen Versionen von awk) der hinzugefügten führenden Leerzeichen:

$ echo '1 2 3 4 5 6 7 8' | awk '{ $1=$2=$3="";$0=$0;} NF=NF'
4 5 6 7 8

Option 3

Durch Drucken jedes mit formatierten Felds erhalten Sie printfmehr Kontrolle:

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=3 '{ for (i=n+1; i<=NF; i++){printf("%s%s",$i,i==NF?RS:OFS);} }'
4 5 6 7 8

Alle vorherigen Antworten ändern jedoch alle FS zwischen Feldern in OFS. Lassen Sie uns ein paar Lösungen dafür entwickeln.

Option 4

Eine Schleife mit Sub zum Entfernen von Feldern und Trennzeichen ist portabler und löst keine Änderung von FS zu OFS aus:

$ echo '    1    2  3     4   5   6 7     8  ' |
awk -v n=3 '{ for(i=1;i<=n;i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 '
4   5   6 7     8

HINWEIS: Mit "^ [" FS "] *" wird eine Eingabe mit führenden Leerzeichen akzeptiert.

Option 5

Es ist durchaus möglich, eine Lösung zu erstellen, die keine zusätzlichen führenden oder nachfolgenden Leerzeichen hinzufügt und vorhandene Leerzeichen mithilfe der Funktion gensubvon GNU awk wie folgt beibehält:

$ echo '    1    2  3     4   5   6 7     8  ' |
awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }'
4   5   6 7     8 

Es kann auch verwendet werden, um eine Feldliste mit einer bestimmten Anzahl auszutauschen n:

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=3 '{ a=gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1);
                b=gensub("^(.*)("a")","\\1",1);
                print "|"a"|","!"b"!";
               }'
|4   5   6 7     8  | !    1    2  3     !

In diesem Fall wird das OFS natürlich verwendet, um beide Teile der Zeile zu trennen, und der nachfolgende Leerraum der Felder wird weiterhin gedruckt.

Hinweis 1: ["FS"]* wird verwendet, um führende Leerzeichen in der Eingabezeile zuzulassen.


Hallo BZ Deine Antwort ist nett. Option 3 funktioniert jedoch nicht für Zeichenfolgen, die mit einem Leerzeichen beginnen (z " 1 2 3 4 5 6 7 8 ". B. ). Option 4 ist nett, aber lassen Sie ein führendes Leerzeichen mit einer Zeichenfolge, die mit einem Leerzeichen beginnt. Denken Sie, ob dies reparabel ist? Sie können Befehl echo " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'verwenden, um führende / mittlere /
nachfolgende

Hallo @olibre. Dass die Option 3 mit Leerzeichen fehlschlägt, ist der Grund für die Entwicklung der Optionen 4 und 5. Option 4 lässt nur dann ein führendes Leerzeichen übrig, wenn die Eingabe dies hat und n auf 0 gesetzt ist (n = 0). Das glaube ich ist die richtige Antwort, wenn es keine Auswahl von Feldern gibt (nichts, um IMO zu reparieren). Prost.

Gut. Vielen Dank für die zusätzlichen Informationen :-) Bitte verbessern Sie Ihre Antwort mit diesen zusätzlichen Informationen :-) Cheers
olibre

Perfekt :-) Wie schade, dass Ihr Benutzer deaktiviert ist :-(
olibre

1

Cut verfügt über ein --complement-Flag, mit dem Spalten einfach (und schnell) gelöscht werden können. Die resultierende Syntax entspricht der gewünschten Syntax, sodass die Lösung leichter zu lesen und zu verstehen ist. Komplement funktioniert auch für den Fall, dass Sie nicht zusammenhängende Spalten löschen möchten.

$ foo='1 2 3 %s 5 6 7'
$ echo "$foo" | cut --complement -d' ' -f1-3
%s 5 6 7
$

Können Sie bitte Ihre Antwort näher erläutern?
Zulu

Hilft die obige Bearbeitung beim Verständnis? Der Punkt ist, die Komplement-Flagge des Schnitts zu verwenden. Die Lösung sollte schneller und präziser implementiert werden als AWK- oder Perl-basierte Lösungen. Es können auch beliebige Spalten geschnitten werden.
Michael zurück

1

Perl-Lösung, die keine führenden oder nachfolgenden Leerzeichen hinzufügt:

perl -lane 'splice @F,0,3; print join " ",@F' file

Das Perl- @FAutosplit-Array beginnt am Index, 0während awk-Felder mit beginnen$1


Perl-Lösung für durch Kommas getrennte Daten:

perl -F, -lane 'splice @F,0,3; print join ",",@F' file

Python-Lösung:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file


0

Für mich ist die kompakteste und konformste Lösung für die Anfrage

$ a='1   2\t \t3     4   5   6 7 \t 8\t '; 
$ echo -e "$a" | awk -v n=3 '{while (i<n) {i++; sub($1 FS"*", "")}; print $0}'

Und wenn Sie mehr Zeilen als beispielsweise die Datei foo.txt verarbeiten müssen, vergessen Sie nicht, i auf 0 zurückzusetzen:

$ awk -v n=3 '{i=0; while (i<n) {i++; sub($1 FS"*", "")}; print $0}' foo.txt

Danke dein Forum.


0

Da ich mich über die erste hoch bewertete, aber falsche Antwort geärgert habe, habe ich genug gefunden, um dort eine Antwort zu schreiben, und hier sind die falschen Antworten als solche gekennzeichnet, hier ist mein Teil. Ich mag keine vorgeschlagenen Lösungen, da ich keinen Grund sehe, die Antwort so komplex zu gestalten.

Ich habe ein Protokoll, in dem nach $ 5 mit einer IP-Adresse mehr Text oder kein Text sein kann. Ich brauche alles von der IP-Adresse bis zum Ende der Leitung, sollte es nach 5 Dollar etwas geben. In meinem Fall ist dies tatsächlich ein awk-Programm, kein awk-Oneliner, also muss awk das Problem lösen. Wenn ich versuche, die ersten 4 Felder mit der alten, gut aussehenden und am besten bewerteten, aber völlig falschen Antwort zu entfernen:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'

es spuckt falsche und nutzlose Antworten aus (ich habe [] hinzugefügt, um zu demonstrieren):

[    37.244.182.218 one two three]

Wenn die Spalten eine feste Breite haben, bis der Schnittpunkt und awk benötigt werden, lautet die richtige und recht einfache Antwort:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{printf "[%s]\n", substr($0,28)}'

welches die gewünschte Ausgabe erzeugt:

[37.244.182.218 one two three]

0

Ich habe diese andere Möglichkeit gefunden, vielleicht könnte sie auch nützlich sein ...

awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file

Hinweis: 1. Für tabellarische Daten und von Spalte $ 1 bis $ 14


0

Verwenden Sie Schnitt:

cut -d <The character between characters> -f <number of first column>,<number of last column> <file name>

zB: Wenn Sie file1enthalten haben:car.is.nice.equal.bmw

Ausführen: cut -d . -f1,3 file1 wird gedrucktcar.is.nice


Ihre Lösung scheint möglicherweise rückwärts zu sein. Bitte überprüfen Sie den Titel der Frage Drucken Sie alle * außer * die ersten drei Spalten
Stefan Crain

-1

Dies ist nicht sehr weit von einigen der vorherigen Antworten entfernt, löst jedoch einige Probleme:

cols.sh::

#!/bin/bash
awk -v s=$1 '{for(i=s; i<=NF;i++) printf "%-5s", $i; print "" }'

Was Sie jetzt mit einem Argument aufrufen können, das die Startspalte sein wird:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 3 
3    4    5    6    7    8    9    10   11   12   13   14

Oder:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 
7    8    9    10   11   12   13   14

Dies ist 1-indiziert; Wenn Sie eine Nullindizierung bevorzugen, verwenden Sie i=s + 1stattdessen.

Wenn Sie außerdem Argumente für den Startindex und den Endindex benötigen, ändern Sie die Datei in:

#!/bin/bash
awk -v s=$1 -v e=$2 '{for(i=s; i<=e;i++) printf "%-5s", $i; print "" }'

Beispielsweise:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 9 
7    8    9

Das %-5srichtet das Ergebnis als 5 Zeichen breite Spalten aus. Wenn dies nicht ausreicht, erhöhen Sie die Anzahl oder verwenden %sSie stattdessen (mit einem Leerzeichen), wenn Sie sich nicht für die Ausrichtung interessieren.


-1

AWK printf-basierte Lösung, die% -Probleme vermeidet und insofern einzigartig ist, als sie nichts zurückgibt (kein Rückgabezeichen), wenn weniger als 4 Spalten gedruckt werden müssen:

awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'

Testen:

$ x='1 2 3 %s 4 5 6'
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
%s 4 5 6
$ x='1 2 3'
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
$ x='1 2 3 '
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
$
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.