ubuntuusers.de

Suche Tipps: Suchen+Einfügen-Skript verbessern

Status: Gelöst | Ubuntu-Version: Kubuntu 10.10 (Maverick Meerkat)
Antworten |

cocons

Anmeldungsdatum:
4. August 2008

Beiträge: 34

Hi! Ich habe "mal schnell" für einen Bekannten ein Skript schreiben wollen um Datensätze zu konvertieren. Er bekommt ein Datei wo jeweils in einer Zeile ein Datensatz steht. Ohne Komma oder Semikolon getrennt. Jetzt habe ich ein Skript zusammengemurkst was also per cut die Datei zerlegt und mit Semikola versieht. Jetzt läuft es schon seit Stunden, es braucht ungefähr 0.5s pro Zeile. Das dauert bei über 80.000 Zeilen ja Tage ☹

cat ORIGINALDATEI | while read line; do
        newline="`echo "$line"|cut -b 1-1 -`;"
	newline=$newline"`echo "$line"|cut -b 2-11 -`;"
	newline=$newline"`echo "$line"|cut -b 12-31 -`;"
	newline=$newline"`echo "$line"|cut -b 32-34 -`;"
	newline=$newline"`echo "$line"|cut -b 35-43 -`;"
	newline=$newline"`echo "$line"|cut -b 44-44 -`;"
        # usw usf...
    echo "$newline"
    echo $newline >> neu.csv
done

Hat jemand eine gute Idee wie man sowas verbessern könnte damit es schneller geht?

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Ja. ☺

Probier mal sedhttp://www.tty1.net/sed-tutorium/sed-tutorium.html

Dein Ding muss ja ewig rödeln, wenn es pro Zeile 256 Programme 5x verschachtelt aufruft ...
(und außerdem kann cut -b eine böse Falle sein, falls Umlaute und Sonderzeichen vorkommen.
Dann schneidet es nämlich falsch, weil solche Zeichen in utf-8 mehrere Bytes lang sind.)

Wenn Du einen konkreten Tip möchtest, solltest Du mal einen Muster-Datensatz posten,
wie er vorher aussieht und wie er hinterher aussehen soll.

(ich kapiere nämlich noch nicht genau was Du willst. Einfach nur Leerzeichen durch ";" ersetzten, oder ist es komplizierter ?)

track

cocons

(Themenstarter)

Anmeldungsdatum:
4. August 2008

Beiträge: 34

Hallo! Danke für die schnelle Antwort! track schrieb:

(ich kapiere nämlich noch nicht genau was Du willst. Einfach nur Leerzeichen durch ";" ersetzten, oder ist es komplizierter ?) track

Umlaute und Sonderzeichen kommen glücklicherweise nicht vor. Nicht ersetzen sondern an festen Stellen einfügen, es soll also nichts weggeschmissen werden! Hier ein Beispiel: Original

12345678900KUPPLUNG            4560000088123456A 00000006DD EUR4111111120333 2305566000  14765NL            22882 NL           *

Nach der Bearbeitung:

2;5030260961;HUELSEN             ;313;000004000;3;002;P ;0000234;0;MM ;EUR;3;0000052;10333 ;8205599000  ;05035;AT ;          ; ;11201; DE          ; ;*;

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

???
Das ist doch niemals der selbe Datensatz "vorher" und "nachher" !

Verstehe ich es richtig, dass Du einfach stumpf an festgelegten Positionen ";" einfügen willst ?

Dann brauchst Du in der Tat nicht einmal sed, sondern kannst es einfach in der Shell mit einer Serie Parameter Expansions erledigen:

while read line; do
        echo -n "${line:0:1};"		# Beachte: der String wird ab "0" gezählt.
        echo -n "${line:1:10};"
        echo -n "${line:11:20};"
        echo -n "${line:31:3};"
        echo -n "${line:34:8};"
        echo -n "${line:43:1};"
        echo -n "${line:44:7};"
        echo -n "${line:51:6};"
        echo -n "${line:57:12};"
        echo -n "${line:69:5};"
        echo -n "${line:74:3};"
    # usw ...
        echo "${line:127:1};"		# die letzte mit Zeilenende, ohne "-n"

done  <  "$originaldatei"  >  "neu.csv"

Die zählen ganz nebenbei auch richtig die Buchstaben (und nicht die Bytes).

LG,

track

cocons

(Themenstarter)

Anmeldungsdatum:
4. August 2008

Beiträge: 34

Vielen Dank Track!

track schrieb:

???
Das ist doch niemals der selbe Datensatz "vorher" und "nachher" !

Ja, ich habe einfach 2 beliebige Zeilen aus vorher-nachher kopiert.

Verstehe ich es richtig, dass Du einfach stumpf an festgelegten Positionen ";" einfügen willst ?

Genau!

Nachtrag: Ich habe das jetzt mal komplett umgesetzt und nun läuft es schon einige Zeit. So grob überschlagen dauert es jetzt noch 2-3 Stunden statt einem Tag! Das ist zwar immer noch kein Fingerschnippen, aber mehr würde mal wohl nur mit einem C-Programm erreichen. Und da die Datei nur 2-3 Mal im Jahr kommt lohnt der Aufwand eigentlich nicht.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Jetzt habe ich es doch mal getestet:

track@lucid:~$ for (( i=1; i<=80000; i++ )); do
    zeile="$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM"
    zeile="$zeile$zeile$zeile$zeile$zeile"
    echo "${zeile:0:128}"
done  >  testdatei
track@lucid:~$ wc  testdatei
   80000    80000 10320000 testdatei
track@lucid:~$ time    while read line; do
         echo -n "${line:0:1};"
         echo -n "${line:1:10};"
         echo -n "${line:11:20};"
         echo -n "${line:31:3};"
         echo -n "${line:34:8};"
         echo -n "${line:43:1};"
         echo -n "${line:44:7};"
         echo -n "${line:51:6};"
         echo -n "${line:57:12};"
         echo -n "${line:69:5};"
         echo -n "${line:74:3};"
     # usw ...
         echo "${line:127:1};"
 
done  <  "testdatei"  >  "test_neu.csv"

real	5m24.150s
user	3m3.607s
sys	0m32.102s

Das ist ja schon ganz nett, selbst auf meinem 1 GHz- Athlon ... ☺

Dann wollte ich es genau wissen und habe es auch noch mit sed ausprobiert:

track@lucid:~$ time    sed '^s/\(.\)\(.\{10\}\)\(.\{20\}\)\(...\)\(.\{8\}\)\(.\)\(.\{7\}\)\(.\{6\}\)\(.\{12\}\)/\1;\2;\3;\4;\5;\6;\7;\8;\9;/;
    s/\(.\{5\}\)\(.\{13\}\)\(.\)\(.\)$/\1;\2;\3;\4;/' testdatei  >  test_neu2.csv

real	0m36.819s
user	0m23.901s
sys	0m1.000s

Man muss es in 2 Etappen aufteilen, weil bei sed nur 9 Rück-Referenzen möglich sind.
Und auch sonst ist es nicht gerade übersichtlich, - aber dafür läuft es deutlich schneller ... 😲

Zum Nachtrag: Was hast Du denn da für einen Rechner ...?? - viel älter als mein Athlon von 2001 geht doch fast gar nicht.

LG,

track

cocons

(Themenstarter)

Anmeldungsdatum:
4. August 2008

Beiträge: 34

Hi!

Also es ist hier durchgelaufen, 59 Minuten hat es gedauert. Ich habe es noch ein wenig optimiert. Ich hatte einen i=i+1-Zähler drin, der angezeigt wurde und jedesmal ein "clear". Jetzt wird der Zähler einfach mit echo -n $i ausgegeben.

Es sind 23 Einfügungen zu machen und dann teile ich es auch noch auf (Calc kann nur 64.xxx Zeilen) in einzelne csv-Dateien anhand 2er Stellen. Ich baue also erst die newline komplett zusammen, dann wird die in die jeweilige Datei geschrieben:

i=0
cat ORGINALTAB | while read line; do
	newline=`echo -n "${line:0:1};"`
	newline=$newline`echo -n "${line:1:10};"`
	newline=$newline`echo -n "${line:11:20};"`
	newline=$newline`echo -n "${line:31:3};"`
	newline=$newline`echo -n "${line:34:9};"`
	newline=$newline`echo -n "${line:43:1};"`
	newline=$newline`echo -n "${line:44:3};"`
	newline=$newline`echo -n "${line:47:2};"`
	newline=$newline`echo -n "${line:49:7};"`
	newline=$newline`echo -n "${line:56:1};"`
	newline=$newline`echo -n "${line:57:2};"`
	newline=$newline`echo -n "${line:60:3};"`
	newline=$newline`echo -n "${line:63:1};"`
	newline=$newline`echo -n "${line:64:7};"`
	newline=$newline`echo -n "${line:71:6};"`
	newline=$newline`echo -n "${line:77:12};"`
	newline=$newline`echo -n "${line:89:5};"`
	newline=$newline`echo -n "${line:94:3};"`
	newline=$newline`echo -n "${line:97:10};"`
	newline=$newline`echo -n "${line:107:1};"`
	newline=$newline`echo -n "${line:108:5};"`
	newline=$newline`echo -n "${line:113:14};"`
	newline=$newline`echo -n "${line:126:1};"`
	newline=$newline`echo -n "${line:127:1};"`   
	i=$((i+1))
	#echo "$line"|cut -b 12-31 -`;"
	#echo "$newline"
	#clear
	echo -n "$i;"
    echo "$newline" >>"TRF_`echo "${line:57:2}"`.csv";
done

Das ganze läuft auf einem AMD 2,6GHz, allerdings in einer Virtualbox. Ich habe es auch mal in Cygwin ausprobiert, das war ja grottenlangsam.

Jetzt wirds sportlich ☺ Ich teste grad noch das reine aufteilen in die verschiedenen csv. Wenn das flott geht könnte man ja überlegen, da sed draufzulassen.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Was sollen diese ganzen "XYZ`echo ${var:1:2}ABC`" ...??

Das startet doch jedes Mal eine neue Sub-Shell und bedeutet auch nur genau das selbe wie "XYZ${var:1:2}ABC".

Wenn Du das immer noch drin hast, kostet das natürlich Z-e-i-t ...

track

cocons

(Themenstarter)

Anmeldungsdatum:
4. August 2008

Beiträge: 34

track schrieb:

Was sollen diese ganzen "XYZ`echo ${var:1:2}ABC`" ...??

Man! So langsam komme ich dahinter! Bin manchmal echt etwas betriebsblind.

Das ganze läuft jetzt in sagenhaften 2m55 durch mit allen Aufteilungen. Von anfangs 17 Stunden (!!!) runter auf knapp 3 Minuten! Was in der alten bash noch drinsteckt!

Antworten |