itoss
Anmeldungsdatum: 4. April 2014
Beiträge: 419
|
Hallo, ich versuche gerade Strings mit awk zu filtern Ist es möglich mehrere Felder mit einer %-s Formatierung zusammen zu fassen ? sprich : | echo $STRING | | awk -F " " '{printf "%-s %4s %-s \n" , $1, $2, $14-$25 }'
|
sollte dann als Ausgabe eine Formatierungsvorgabe für Feld 2 liefern und ab Feld 2 die Felder 14-25 unformatiert ausgeben. Das vollständige Auflisten von | echo $STRING | | awk -F " " '{printf "%-s %4s %-s %-s %-s %-s %-s %-s %-s %-s %-s \n" , $1, $2, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24,$25 }'
|
ist doch recht umständlich Bearbeitet von rklm: Titel auf Wunsch des Themenstartes geändert
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4577
Wohnort: Berlin
|
@itoss: Tut das was Du willst?
| #!/usr/bin/awk -f
{
printf("%-s %4s", $1, $2);
for (i = 14; i <= 25; i++) {
printf("%s%-s", OFS, $i);
}
print "";
}
|
Testlauf:
$ echo {1..30} | ./test.awk
1 2 14 15 16 17 18 19 20 21 22 23 24 25
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12821
|
Geht auch ohne awk : | $ echo {1..30} | while read -r a b r; do printf '%s %4s %s\n' "$a" "$b" "$r"; done
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
☺
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4577
Wohnort: Berlin
|
@rklm: Geht sicher auch ohne AWK aber so nicht, denn da wird deutlich zu viel ausgegeben.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12821
|
Marc_BlackJack_Rintsch schrieb: @rklm: Geht sicher auch ohne AWK aber so nicht, denn da wird deutlich zu viel ausgegeben.
Wieso? Woher weißt Du denn, dass die Eingabe mehr Felder hat als die Ausgabe haben soll?
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4577
Wohnort: Berlin
|
@rklm: Im ersten Beitrag werden die Felder 1 und 2 und dann die Felder 14 bis 25 ausgegeben. Ich weiss natürlich nicht ob es nach 25 noch welche in der Eingabe gibt, aber die von 3 bis 13 muss es in der Eingabe ja geben und die sollen nicht ausgegeben werden.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12821
|
Marc_BlackJack_Rintsch schrieb: @rklm: Im ersten Beitrag werden die Felder 1 und 2 und dann die Felder 14 bis 25 ausgegeben. Ich weiss natürlich nicht ob es nach 25 noch welche in der Eingabe gibt, aber die von 3 bis 13 muss es in der Eingabe ja geben und die sollen nicht ausgegeben werden.
Ich Blindfisch. Danke für die Brille!
|
itoss
(Themenstarter)
Anmeldungsdatum: 4. April 2014
Beiträge: 419
|
viele Wege führen nach Rom - ich suche nach der "Autobahn ohne Schlaglöcher" 😉 Die Beispiele mit den Schleifen funktionieren zwar, machen den Code aber unleserlicher, komplizierter, und langsamer. Von der Syntax her würde ich gern bei AWK bleiben. gibt es keine AWK interne Funktion, ähnlich wie : | echo "S T R I N G" | cut -d " " -f1,3-5
|
| echo "S T R I N G" | awk -F " " '{printf "%-s %-s %5-s %-s \n",$1, $3, $4, $5 }'
|
Bei 30 Feldern und mehr werden die Zeilen extrem lang und unübersichtlich, abgesehen davon ist eine interne AWK Stringverarbeitung wesentlich schneller als eine Schleife. AWK hat Cut gegenüber den Vorteil in einem Durchlauf mehrere Feldseparatoren zu definieren ⇒ echo string | awk -F "[: ]" # für : und Leerzeichen als Feldseparator - wüsste nicht wie das mit cut geht ?!
|
kB
Supporter, Wikiteam
Anmeldungsdatum: 4. Oktober 2007
Beiträge: 8616
Wohnort: Münster
|
itoss schrieb: […] awk […] Ist es möglich mehrere Felder mit einer %-s Formatierung zusammen zu fassen ?
Nein. Das Format "%-s" fasst bei printf nichts zusammen, sondern gibt ein Argument als linksbündigen String aus. awk und printf kennen das Konzept „Bereich von Variablen“ nicht.
[…]
Das vollständige Auflisten von | echo $STRING | | awk -F " " '{printf "%-s %4s %-s %-s %-s %-s %-s %-s %-s %-s %-s \n" , $1, $2, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24,$25 }'
|
ist doch recht umständlich
Für wiederkehrende Aufgaben haben die Programmierer schon vor langer Zeit das Konzept „Schleife“ erfunden. Sie führt auch hier zum Ziel, wie Dir bereits gezeigt wurde: echo $STRING | awk -F " " '{printf $1; printf $2; for(i=14; i<=25; i++) printf $i }'
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4577
Wohnort: Berlin
|
@kB: Bei printf sollte man niemals den Formatstring weg lassen, sonst bekommt man Probleme wenn in dem Wert den man versucht auszugeben etwas enthalten ist was einem gültigen Formatstring entspricht:
$ echo 'foo' | awk '{printf $1; print ""}'
foo
$ echo 't%s==0' | awk '{printf $1; print ""}'
awk: (FILENAME=- FNR=1) fatal: not enough arguments to satisfy format string
`t%s==0'
^ ran out for this one
Also eher so:
| echo $STRING | awk -F " " '{print $1, $2; for(i=14; i<=25; i++) printf "%s%s", OFS, $i; print ""}'
|
|
itoss
(Themenstarter)
Anmeldungsdatum: 4. April 2014
Beiträge: 419
|
Das Schleifen auch innerhalb des printf Befehls funktionieren ist zwar ne tolle Sache aber der Gesamtstring ist jetzt noch länger 🤓 ohne schleife und unformatierte Ausgabe
| echo "$STRING" | awk '{print $1, $4, $5, $6, $7, $8, $9, $2, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20,$21, $22, $23, $24}'
|
jetzt könnte man den o.g. Ausgabestring mit u.g. awk Bearbeitung für alle Felder gleich formatieren | echo "$OBRIGER_AUSGABESTRING" | awk '{for(i=1; i<=25; i++) printf "%s%s", OFS, $i; print ""}'
|
um auf das gleiche Ergebnis wie in Bsp. 1 zu kommen ohne Zeilenumbruch : | echo "$STRING" | awk '{printf "%s %s %s %s %s %s %s %s", $1, $4, $5, $6, $7, $8, $9, $2; for(i=11; i<=25; i++) printf "%s%s", OFS, $i; print ""}'
|
nehme ich für den ersten teil nur print | echo "$STRING" | awk '{print $1, $4, $5, $6, $7, $8, $9, $2; for(i=11; i<=25; i++) printf "%s%s", OFS, $i; print ""}'
|
habe ich ein Zeilenumbruch nach der $2 Ausgabe.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
itoss schrieb: | echo "$STRING" | awk '{print $1, $4, $5, $6, $7, $8, $9, $2, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20,$21, $22, $23, $24}'
|
Jetzt hast Du Dein Beispiel aber noch "mal eben" ganz gehörig erweitert ... Aber ok - Du wolltest einen Bereichs-"Operator". Den gibt es bei awk nicht, aber bei der Shell: track@track:~$ echo x{1..25} | bash -c 'read -a x; for i in 0 {3..8} 1 {13..24}; do printf "%s " ${x[i]}; done; echo'
x1 x4 x5 x6 x7 x8 x9 x2 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 (Ja, alle Indizes werden von 0 statt von 1 an gezählt, aber das ist bei Shell-Arrays so.) Bei awk kannst Du die Zahlen mit split direkt in ein Array übergeben: track@track:~$ echo x{1..25} | awk '{split("1 4 5 6 7 8 9 2 14 15 16 17 18 19 20 21 22 23 24 25",a); for(i=1;a[i];i++) printf "%s ",$a[i]; print ""}'
x1 x4 x5 x6 x7 x8 x9 x2 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 ... oder Du regelst die Sprünge in der Liste mit entsprechenden Bedingungen: track@track:~$ echo x{1..25} | awk '{for(i=1;i<=25;i++) {if(i==2)i=4; if(i==10)i=2; if(i==3)i=14; printf "%s ",$i}; print ""}'
x1 x4 x5 x6 x7 x8 x9 x2 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 Das ist zwar alles nicht so elegant, wie Du es Dir vorgestellt hast, aber andere Varianten wüsste ich jetzt auch nicht. LG, track
|
kB
Supporter, Wikiteam
Anmeldungsdatum: 4. Oktober 2007
Beiträge: 8616
Wohnort: Münster
|
Was ist eigendlich Dein Ziel?
Willst Du den Befehl cut in awk nachprogrammieren? Ja, das geht, erfordert aber einige Zeilen, wenn man es übersichtlich darstellen und vollständig machen möchte. Oder willst Du einfach die Reihenfolge der Felder ändern und einige auslassen? Das macht cut perfekt. Nutze es. Oder was?
|
itoss
(Themenstarter)
Anmeldungsdatum: 4. April 2014
Beiträge: 419
|
Gut - eine einfache Einzeilerlösung ohne Schleife gib es wohl nicht. am schnellsten ist die Variante : | echo "$STRING" | awk -F "[ab]" '{print $1, $4, $5, $6, $7, $8, $9, $2, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20,$21, $22, $23, $24}'
|
track, wirklich kürzer ist die Schreibweise auch nicht (unter 25 Feldern ) 🙄 - aber trotzdem danke für die Bespiele 😉 kb, im Prinzip suchte ich eine cut Lösung mit mehrfachen Feldtrenner. Cut interpretiert allerdings jedes Leerzeichen als Feld, sind es mehrere Leerzeichen nach einander werden diese von awk als ein Leerzeichen gesehen, und die Felder dementsprechend gezählt, bei cut irgentwie nicht.
|
kB
Supporter, Wikiteam
Anmeldungsdatum: 4. Oktober 2007
Beiträge: 8616
Wohnort: Münster
|
itoss schrieb: […] im Prinzip suchte ich eine cut Lösung mit mehrfachen Feldtrenner. Cut interpretiert allerdings jedes Leerzeichen als Feld, sind es mehrere Leerzeichen nach einander werden diese von awk als ein Leerzeichen gesehen, und die Felder dementsprechend gezählt, bei cut irgentwie nicht.
cut trennt die Felder bei einem bestimmten Zeichen. Dieses ist per Vorgabe der Tabulator, kann aber mit der Option -d auf jedes andere einzelne Zeichen gesetzt werden. awk trennt die Felder an Stellen, die einem regulären Ausdruck entsprechen. Dieses ist per Vorgabe white space, kann aber mit der Option -F bzw. per Variable FS auf einen beliebigen regulären Ausdruck gesetzt werden. Wenn Du Zeichenfolgen als Trenner verwenden willst, geht das also nicht mit cut, aber natürlich per awk. Eine andere Möglichkeit wäre, vorher jedes Vorkommen von white space zu normalisieren, z.B. auf einen einzelnen Tabulator und dann für das Umsortieren der Felder cut zu verwenden. Dann geht natürlich auch die von Dir so geschätzte Bereichsauswahl. Die Normalisierung von white space gelingt z.B. mit sed: sed -r 's/\s+/\t/' EINGABEDATEI | cut -f1,4,5-9,2-11-
|