Hallo, Am Mit, 31 Jan 2007, Sandy Drobic schrieb:
David Haller wrote:
Am Mit, 31 Jan 2007, Sandy Drobic schrieb: [Loesung mit shell + awk in Schleife] *uargs* Sorry Sandy, aber das ist ganz übel... *SCNR*
Grins! Verübeln tue ich es dir nicht. (^-°)
*g* Du hast halt das, was awk am besten kann, mehr oder weniger gut mit der shell gemacht. Wenn du das raussuchen der Felder etc. auch noch mit shell-Mitteln gemacht hättest, hätt's kein "uargs" gegeben (nur den Hinweis, daß es mit awk vielleicht einfacher ist). Hier ne Bash Lösung: ==== #!/bin/bash declare -a A cnt=0 while read line; do IFS=";" A=( $line ) if test "x${A[0]}" = "xKUNDENKARTE"; then cnt=$(( cnt + 1 )) A[5]='' ## irgendwie wird ein Feld gefressen, und ohne das ## hier landet $cnt in Feld 6 fi printf "%s;%s;%s;%s;%s;%s;%06i\n" "${A[@]}" $cnt done ==== BTW: ja, das ist verwendet "Bashismen" ;) Speziell der Trick mit dem Aufspalten (an $IFS) ins Array ist bash-spezifisch. Traditionell geht's aber auch (read f1 f2 .. f6, ich bekomme hier aber gerade immer ein ';' zuviel oder hinter "KUNDENKARTE" ein leeres Feld zuwenig (s.o.)). Deswegen jetzt keine Lösung nur mit bourne-shell Mitteln.
Aber für "mal eben schnell in der Mittagspause hinschreiben" hat es mir gereicht. Bis ich die Optionen für AWK alle zusammengesucht hätte, wäre das umständlichere Script schon durchgelaufen.
*g* Ja, kann ich verstehen.
$ awk 'BEGIN { FS=";"; OFS=";"; } /KUNDENKARTE/{ cnt++; } { $7 = sprintf("%06i", cnt); print; }' /tmp/datei.csv
BTW: das ist noch "faslch"! Richtigerweise ist ja gefordert, das wenn das Feld 1 = "KUNDENKARTE" ist, dann ... Korrekt ist also: awk 'BEGIN { FS=";"; OFS=";"; } $1 == "KUNDENKARTE" { cnt++; } { $7 = sprintf("%06i", cnt); print; }' /tmp/datei.csv Ggfs. kann man die Bedingung natürlich auch anders (z.B. als Regex) formulieren, was aber nur sinnvoll ist, wenn das Feld z.B. nur mit KUNDENKARTE beginnen muß, aber vor dem ';' noch weiteres enthalten könnte. Das könnte man dann so machen: awk 'BEGIN { FS=";"; OFS=";"; } $1 ~ /^KUNDENKARTE/ { cnt++; } { $7 = sprintf("%06i", cnt); print; }' /tmp/datei.csv Da würde cnt auch erhöht, wenn im ersten Feld z.B. KUNDENKARTE_MIT_RABATT stehen würde (oder sonstwas, auf das die RE eben passt ;)
Ich nehme mir schon die ganze Zeit vor, diese Textwerkzeuge einmal eine Woche lang durchzuackern, aber es kommt immer eine andere Sache, die höhere Priorität hat. :-/
*g* Wobei das, was ich verwendet habe (FS entspricht der Option '-F' auf der Kommandozeile, und OFS ist das Gegenstück für die Ausgabe, in der manpage nicht gerade schwer zu finden ;) sind eigentlich grundlegende Dinge bei awk. Was man schon daran sieht, daß ich ohne GNU awk Erweiterungen auskomme ;) Und es sind ja nur 3 Muster + Block: Muster: BEGIN # wird zum Script-start ausgeführt Block: Setze FS und OFS jew. auf ';' (Option -F';' setzt FS=";") Muster: $1 == "KUNDENKARTE" # Feld 1 ist der String in "" Block: { cnt++; } # addiere 1 zu cnt Muster: <keins> # passt auf jede Zeile (=> Siehe auch # Variable RS / Record-Seperator) Block: - Feld 7 per sprintf setzen - Ausgabe per print, Details siehe Doku (insbesondere, daß die Felder mit dem ersten Zeichen aus OFS zusammengepappt werden. Und die jew. print werden mittels ORS zusammengepappt). Dafür muß man nicht viel mehr, als einmal die manpage durcharbeiten (kein Vorwurf!). Der Algorithmus ist jeweils der, den du schon bei deiner Lösung verwendet hast. Und die awk-Lösung ist eben einfach ;)
Im Standard http://www.opengroup.org/onlinepubs/007908799/xcu/awk.html sind alle drei Varianten drin und mit GNU awk -W traditional etc. bekomme ich keine Warnungen. Es sollte also auch 'cnt++' portabel sein.
Da ich nicht viele Oldtimer unter meinen Systemen habe, sollte es auch mit cnt++ gehen. Den Linke jedenfalls habe ich mir notiert, das geht etwas schneller als sich die Optionen über "man awk" zusammenzusuchen.
Hä? Das sind doch praktisch die Manpages, nur eben in der Version, die dem Standard entspricht bzw. diesen definiert ;) Aber wie gesagt: die Operatoren ++ <als PREFIX> und <als POSTFIX> ++ scheinen von Anfang an bei awk dabeigewesen zu sein. Ob's (ältere, exotischere) Implementationen gibt, die das nicht implementieren weiß ich nicht. Vergleiche dagegen mal die Features von http://www.opengroup.org/onlinepubs/007908799/xcu/find.html mit denen der GNU find Variante... (Mist, das ist alles SUSv2, aktuell ist SUSv3, da ist dann bei find IIRC z.B. das '-exec ... {} +' definiert, das es bei GNU find nicht gibt... Ah, halt, da: http://www.unix.org/version3/ gibt's wohl die aktuelle Version, da muß man sich aber registrieren (weiter hab ich jetzt nicht geschaut) :)) Die Experten (speziell zu Standards und Portabilität) sind z.B. in de.comp.os.unix.shell zu finden ;) Aber mit so Details würde ich mich an deiner Stelle noch nicht befassen. Wenn's in einer Man/Infopage Abschnitte mit einem Titel wie "CONFORMING TO", "POSIX COMPATIBILITY", "GNU EXTENSIONS" o.ä. gibt, dann sollte man sich den durchlesen und sich ungefähr merken, welche Features betroffen sind... Speziell jemand wie du, der auch (mal) unter anderen (und älteren) Unices hantiert ;) BTW: ein Script, das unter der 'ash' läuft, kann man AFAIK als Bourne-kompatibel (d.h. portabel) ansehen. Aber ein explizites(!) (d.h. mit "#!/bin/bash" deklariertes) Bash-script ist manchmal sinnvoll(er) *g*. -dnh PS: melde dich ruhig auch mal per PM ;) -- D: is just a data disk. That's why it's called "D", for "DATA". C: is the Windows OS disk, so it's called "C", for "CRAP". -- David P. Murphy -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org