it-swarm.com.de

Verwenden Sie awk, um alle Spalten von der n-ten bis zur letzten zu drucken

Diese Linie funktionierte, bis ich im zweiten Feld Whitespace hatte.

svn status | grep '\!' | gawk '{print $2;}' > removedProjs

gibt es eine Möglichkeit, awk alles in 2 $ oder mehr drucken zu lassen? ($ 3, $ 4 ... bis wir keine Spalten mehr haben?)

Ich denke, ich sollte hinzufügen, dass ich dies in einer Windows-Umgebung mit Cygwin mache.

249
Andy

druckt alle bis auf die erste Spalte:

awk '{$1=""; print $0}' somefile

druckt alle außer zwei ersten Spalten:

awk '{$1=$2=""; print $0}' somefile
404
zed_0xff

Es gibt eine doppelte Frage mit einer einfacheren Antwort using cut:

 svn status |  grep '\!' | cut -d\  -f2-

-d gibt das Trennzeichen (Leerzeichen) an, -f gibt die Liste der Spalten an (alle beginnend mit der 2.)

87
Joshua Goldberg

Sie können eine for-Schleife verwenden, um durch die Druckfelder $ 2 bis $ NF zu blättern (integrierte Variable, die die Anzahl der Felder in der Zeile darstellt).

Edit: Da "print" eine neue Zeile anfügt, sollten Sie die Ergebnisse zwischenspeichern:

awk '{out=""; for(i=2;i<=NF;i++){out=out" "$i}; print out}'

Alternativ können Sie printf verwenden:

awk '{for(i=2;i<=NF;i++){printf "%s ", $i}; printf "\n"}'
71
VeeArr
awk '{out=$2; for(i=3;i<=NF;i++){out=out" "$i}; print out}'

Meine Antwort basiert auf der von VeeArr , aber ich bemerkte, dass sie mit einem Leerzeichen begann, bevor die zweite Spalte (und der Rest) gedruckt wurde. Da ich nur einen Reputationspunkt habe, kann ich nichts dazu sagen, deshalb geht es hier um eine neue Antwort:

beginnen Sie mit "out" als zweite Spalte und fügen Sie dann alle anderen Spalten hinzu (falls vorhanden). Dies geht gut, solange es eine zweite Spalte gibt.

21
Wim

Ich habe alle oben genannten Antworten persönlich ausprobiert, aber die meisten waren etwas komplex oder einfach nicht richtig. Der einfachste Weg, dies aus meiner Sicht zu tun, ist:

awk -F" " '{ for (i=4; i<=NF; i++) print $i }'
  1. Dabei definiert -F "" das Trennzeichen, das awk verwenden soll. In meinem Fall ist das Leerzeichen, das auch das Standardtrennzeichen für awk ist. Dies bedeutet, dass -F "" ignoriert werden kann.

  2. Dabei definiert NF die Gesamtzahl der Felder/Spalten. Daher beginnt die Schleife vom vierten Feld bis zum letzten Feld/Spalte.

  3. Dabei gibt $ N den Wert des N-ten Felds ab. Deshalb druckt print $ i das aktuelle Feld/die aktuelle Spalte basierend auf der Anzahl der Schleifen.

12
koullislp

Die meisten Lösungen mit awk lassen einen Freiraum. Die Optionen hier vermeiden dieses Problem.

Option 1

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

command | cut -d' ' -f3-

Option 2

Beim Erzwingen eines erneuten Berechnens von awk entfernen Sie manchmal den hinzugefügten führenden Leerraum (OFS), indem Sie die ersten Felder entfernen (funktioniert mit einigen Versionen von awk):

command | awk '{ $1=$2="";$0=$0;} NF=NF'

Option 3

Wenn Sie jedes mit printf formatierte Feld drucken, erhalten Sie mehr Kontrolle:

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

Alle vorherigen Antworten ändern jedoch alle wiederholten FS zwischen Feldern in OFS. Lassen Sie uns ein paar Optionen erstellen, die das nicht tun.

Option 4 (empfohlen)

Eine Schleife mit U-Bahn zum Entfernen von Feldern und Trennzeichen an der Vorderseite.
Und den Wert von FS anstelle von Leerzeichen verwenden (das geändert werden kann).
Ist portabler und löst keine Änderung von FS in OFS: aus. HINWEIS: Der ^[FS]* akzeptiert eine Eingabe mit führenden Leerzeichen.

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

Option 5

Es ist durchaus möglich, eine Lösung zu erstellen, die keinen zusätzlichen (führenden oder nachgestellten) Leerraum hinzufügt und vorhandene Leerzeichen mithilfe der Funktion gensub von GNU awk wie folgt erhält:

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

Es kann auch verwendet werden, um eine Gruppe von Feldern mit einer Anzahl n auszutauschen:

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

In einem solchen Fall wird der OFS natürlich verwendet, um beide Teile der Linie zu trennen, und der weiße Leerraum der Felder wird immer noch gedruckt.

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

8
user2350426

Das hat mich so sehr irritiert, dass ich mich hingesetzt habe und einen cut-artigen Feldspezer geschrieben habe, der mit GNU Awk 3.1.7 getestet wurde. 

Erstellen Sie zunächst ein neues Awk-Bibliotheksskript mit dem Namen pfcut, mit z.

Sudo nano /usr/share/awk/pfcut

Fügen Sie dann das unten stehende Skript ein und speichern Sie. Danach sieht die Verwendung so aus:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-4"); }'
t1 t2 t3 t4

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("2-"); }'
t2 t3 t4 t5 t6 t7

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7

Um zu vermeiden, all das einzugeben, denke ich, ist das Beste, was man tun kann (siehe anders Beim Start automatisch eine Benutzerfunktion mit awk laden - Unix & Linux Stack Exchange ) ist ein Alias ​​zu ~/.bashrc; z.B. mit:

$ echo "alias awk-pfcut='awk -f pfcut --source'" >> ~/.bashrc
$ source ~/.bashrc     # refresh bash aliases

... dann kannst du einfach anrufen:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk-pfcut '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7

Hier ist die Quelle des pfcut-Skripts:

# pfcut - print fields like cut
#
# sdaau, GNU GPL
# Nov, 2013

function spfcut(formatstring)
{
  # parse format string
  numsplitscomma = split(formatstring, fsa, ",");
  numspecparts = 0;
  split("", parts); # clear/initialize array (for e.g. `tail` piping into `awk`)
  for(i=1;i<=numsplitscomma;i++) {
    commapart=fsa[i];
    numsplitsminus = split(fsa[i], cpa, "-");
    # assume here a range is always just two parts: "a-b"
    # also assume user has already sorted the ranges
    #print numsplitsminus, cpa[1], cpa[2]; # debug
    if(numsplitsminus==2) {
     if ((cpa[1]) == "") cpa[1] = 1;
     if ((cpa[2]) == "") cpa[2] = NF;
     for(j=cpa[1];j<=cpa[2];j++) {
       parts[numspecparts++] = j;
     }
    } else parts[numspecparts++] = commapart;
  }
  n=asort(parts); outs="";
  for(i=1;i<=n;i++) {
    outs = outs sprintf("%s%s", $parts[i], (i==n)?"":OFS); 
    #print(i, parts[i]); # debug
  }
  return outs;
}

function pfcut(formatstring) {
  print spfcut(formatstring);
}
6
sdaau

Würde das funktionieren?

awk '{print substr($0,length($1)+1);}' < file

Es lässt jedoch etwas Leerraum vor.

5
whaley

Spalten beginnend mit # 2 ausgeben (die Ausgabe hat am Anfang kein Leerzeichen):

ls -l | awk '{sub(/[^ ]+ /, ""); print $0}'
5
savvadia
echo "1 2 3 4 5 6" | awk '{ $NF = ""; print $0}'

dieser verwendet awk, um alles außer dem letzten Feld zu drucken

4
Kaushal Jha

Das habe ich allen Empfehlungen vorgezogen:

Druck von der 6. bis zur letzten Spalte.

ls -lthr | awk '{out=$6; for(i=7;i<=NF;i++){out=out" "$i}; print out}'

oder

ls -lthr | awk '{ORS=" "; for(i=6;i<=NF;i++) print $i;print "\n"}'
3
Manuel Parra
awk '{ for(i=3; i<=NF; ++i) printf $i""FS; print "" }'

lauhub schlug diese richtige, einfache und schnelle Lösung vor hier

3
ajendrex

Wenn Sie bestimmte Spalten benötigen, die mit einem beliebigen Trennzeichen gedruckt werden:

awk '{print $3 "  " $4}'

spalte 3 Spalte 4

awk '{print $3 "anything" $4}'

col # 3anythingcol # 4

Wenn Sie also Whitespace in einer Spalte haben, werden es zwei Spalten sein, Sie können sie jedoch mit einem beliebigen Trennzeichen oder ohne Trennzeichen verbinden. 

2
I159

Perl-Lösung:

Perl -lane 'splice @F,0,1; print join " ",@F' file

Diese Befehlszeilenoptionen werden verwendet:

  • -n Durchläuft jede Zeile der Eingabedatei und druckt nicht automatisch jede Zeile

  • -l Entfernt Zeilenumbrüche vor der Verarbeitung und fügt sie anschließend wieder ein

  • -a Autosplit-Modus - Teilen Sie die Eingabezeilen in das @F-Array. Standardmäßig wird auf Leerzeichen aufgeteilt

  • -e Führe den Perl-Code aus

splice @F,0,1 Entfernt Spalte 0 sauber aus dem @F-Array

join " ",@F Fügt die Elemente des @F-Arrays mit einem Leerzeichen zwischen den Elementen zusammen


Python-Lösung:

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

2
Chris Koknat

Dies würde funktionieren, wenn Sie Bash verwenden und Sie könnten so viele 'x' wie Elemente verwenden, die Sie löschen möchten, und mehrere Leerzeichen werden ignoriert, wenn sie nicht mit Escapezeichen versehen sind.

while read x b; do echo "$b"; done < filename
0
Stuart Rothrock

Diese awk-Funktion gibt den Teilstring von $0 zurück, der Felder von begin bis end enthält:

function fields(begin, end,    b, e, p, i) {
    b = 0; e = 0; p = 0;
    for (i = 1; i <= NF; ++i) {
        if (begin == i) { b = p; }
        p += length($i);
        e = p;
        if (end == i) { break; }
        p += length(FS);
    }
    return substr($0, b + 1, e - b);
}

Um alles ab Feld 3 zu erhalten:

tail = fields(3);

So erhalten Sie einen Abschnitt von $0, der die Felder 3 bis 5 abdeckt:

middle = fields(3, 5);

b, e, p, i Unsinn in der Liste Funktionsparameter ist nur ein awk Weg, um lokale Variablen deklarieren.

0
wonder.mice

Perl:

@m=`ls -ltr dir | grep ^d | awk '{print \$6,\$7,\$8,\$9}'`;
foreach $i (@m)
{
        print "$i\n";

}
0
pkm

Wenn Sie den Teil der Zeile, den Sie nicht abhacken, nicht neu formatieren möchten, ist die beste Lösung, die ich mir vorstellen kann, in meiner Antwort geschrieben:

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

Es schneidet das vor der gegebenen Feldnummer N ab und druckt den Rest der Zeile, einschließlich der Feldnummer N und der Beibehaltung des ursprünglichen Abstands (es formatiert nicht neu). Es ist unerheblich, ob die Zeichenfolge des Felds auch an anderer Stelle in der Zeile steht.

Eine Funktion definieren:

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 der Leerzeichen

In Ihrem speziellen Fall:

svn status | grep '\!' | fromField 2 > removedProjs

Wenn Ihre Datei/Ihr Stream keine Zeilen mit neuen Zeilen in der Mitte der Zeilen enthält (Sie könnten einen anderen Datensatztrenner verwenden), können Sie Folgendes verwenden:

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

Der erste Fall schlägt nur in Dateien/Streams fehl, die die seltene hexadezimale Zahl 1 enthalten

0
Robert Vila

Ich möchte die vorgeschlagenen Antworten auf die Situation ausdehnen, in der Felder durch mehrere Leerzeichen abgegrenzt sind - der Grund, warum das OP cut nicht verwendet, nehme ich an.

Ich weiß, dass das OP nach awk gefragt hat, aber ein sed-Ansatz würde hier funktionieren (Beispiel mit Druckspalten von der fünften bis zur letzten):

  • purer sed-ansatz

    sed -r 's/^\s*(\S+\s+){4}//' somefile
    

    Erläuterung:

    • s/// wird standardmäßig zur Ersetzung verwendet
    • ^\s* entspricht einem beliebigen fortlaufenden Leerzeichen am Zeilenanfang
    • \S+\s+ bedeutet eine Spalte mit Daten (Nicht-Whitespace-Zeichen gefolgt von Whitespace-Zeichen)
    • (){4} bedeutet, dass das Muster viermal wiederholt wird.
  • sed und schneiden

    sed -r 's/^\s+//; s/\s+/\t/g' somefile | cut -f5-
    

    indem Sie einfach aufeinanderfolgende Leerzeichen durch eine einzige Registerkarte ersetzen;

  • tr und cut: tr kann auch verwendet werden, um aufeinanderfolgende - Zeichen mit der -s-Option zu quetschen.

    tr -s [:blank:] <somefile | cut -d' ' -f5-
    
0
PlasmaBinturong