Batch Code straffen // Batch File beschleunigen

snailgosh

Newbie
Registriert
Apr. 2018
Beiträge
2
Hallo liebe Community,

ich habe als blutiger Anfänger die Aufgabe bekommen ein batch file zu schreiben, das Koordinaten, die in Mikrometern gespeichert sind, in Meter umrechnen soll.

Nach autodidaktischem Lernen der Syntax und einigem Herumprobieren macht mein File jetzt was es soll.
Leider braucht es dafür sehr, sehr lange. Ich würde mich freuen, wenn ihr mir helft den Code zu straffen und die Syntax in eurem Code erklärt, damit ich dabei noch etwas lerne. :)

Ich erklär die Aufgabenstellung und das File mal Schritt für Schritt.

Mein Input ist eine Datei, in der in der ersten Zeile ein Object1 steht, gefolgt von tausenden Zeilen mit je 9 Spalten. Jede Spalte entspricht einer Koordinate mit sechs Nachkommastellen und ein bis vier Stellen vor dem Komma.

Bsp.:
Code:
Object1
0.000000 0.000000 4.000000 2203.000000 0.000000 4.000000 0.000006 1.000000 4.000000
2203.000000 0.000000 4.000000 0.000000 0.000000 4.000000 0.000000 0.000000 0.000000
2203.000000 1.000000 4.000000 2203.000000 0.000000 4.000000 2203.000000 0.000000 0.000000
0.000006 1.000000 4.000000 2203.000000 1.000000 4.000000 2203.000000 1.000000 0.000000
0.000000 0.000000 4.000000 0.000006 1.000000 4.000000 0.000006 1.000000 0.000000
2203.000000 0.000000 4.000000 0.000000 0.000000 0.000000 2203.000000 0.000000 0.000000
2203.000000 1.000000 4.000000 2203.000000 0.000000 0.000000 2203.000000 1.000000 0.000000
0.000006 1.000000 4.000000 2203.000000 1.000000 0.000000 0.000006 1.000000 0.000000
0.000000 0.000000 4.000000 0.000006 1.000000 0.000000 0.000000 0.000000 0.000000
252.844330 1.187642 0.000000 252.558777 1.000000 0.000000 252.558777 1.000000 0.748811
256.157196 1.188245 0.000000 256.443878 1.000000 3.248366 256.443878 1.000000 0.000000
256.157196 1.188245 0.000000 256.157196 1.188245 4.000000 256.443878 1.000000 3.248366

Das Ziel ist die Ausgabe all dieser Koordinaten in Metern, also um den Faktor 10^6 kleiner. Das "Object1" soll dabei verschwinden.
Bsp.:
Code:
0.000000000000 0.000000000000 0.000004000000 0.002203000000 0.000000000000 0.000004000000 0.000000000006 0.000001000000 0.000004000000
0.002203000000 0.000000000000 0.000004000000 0.000000000000 0.000000000000 0.000004000000 0.000000000000 0.000000000000 0.000000000000
0.002203000000 0.000001000000 0.000004000000 0.002203000000 0.000000000000 0.000004000000 0.002203000000 0.000000000000 0.000000000000
0.000000000006 0.000001000000 0.000004000000 0.002203000000 0.000001000000 0.000004000000 0.002203000000 0.000001000000 0.000000000000
0.000000000000 0.000000000000 0.000004000000 0.000000000006 0.000001000000 0.000004000000 0.000000000006 0.000001000000 0.000000000000
0.002203000000 0.000000000000 0.000004000000 0.000000000000 0.000000000000 0.000000000000 0.002203000000 0.000000000000 0.000000000000
0.002203000000 0.000001000000 0.000004000000 0.002203000000 0.000000000000 0.000000000000 0.002203000000 0.000001000000 0.000000000000
0.000000000006 0.000001000000 0.000004000000 0.002203000000 0.000001000000 0.000000000000 0.000000000006 0.000001000000 0.000000000000
0.000000000000 0.000000000000 0.000004000000 0.000000000006 0.000001000000 0.000000000000 0.000000000000 0.000000000000 0.000000000000
0.000252844330 0.000001187642 0.000000000000 0.000252558777 0.000001000000 0.000000000000 0.000252558777 0.000001000000 0.000000748811
0.000256157196 0.000001188245 0.000000000000 0.000256443878 0.000001000000 0.000003248366 0.000256443878 0.000001000000 0.000000000000
0.000256157196 0.000001188245 0.000000000000 0.000256157196 0.000001188245 0.000004000000 0.000256443878 0.000001000000 0.000003248366
Mein File liest jede Zeile, beginnend mit der Zweiten, aus und speichert den Inhalt jeder der neun Spalten in je einer Variable.
Code:
set /a LineNo=1

:repeat

for /L %%v in (1,1,9) do (
	set "V%%v="
)

for /f "tokens=1-9" %%a in ('more/e +%LineNo% ^< "input.raw"') do (
 
	if defined V1 goto :skipread
	set "V1=%%a"
	set "V2=%%b"
	set "V3=%%c"
	set "V4=%%d"
	set "V5=%%e"
	set "V6=%%f"
	set "V7=%%g"
	set "V8=%%h"
	set "V9=%%i"
)

if not defined V1 goto :eof
:skipread

::hier kommt noch mehr Code hin; siehe weiter unten

set /a LineNo+=1
goto :repeat

Da Batch laut Internetrecherche nicht mit Kommazahlen rechnen kann, kann ich die ausgelesenen Koordinaten nicht einfach durch eine Million teilen. Ich gehe deshalb einen Umweg.

Ich zähle die Anzahl an Zeichen der Variable V (Spalteninhalt) und hänge je nach Anzahl unterschiedlich viele Nullen vorne an.

Code:
for /L %%z in (1,1,9) do (
	set /a "Z%%z=0"
)

set "T1=%V1%"
set "T2=%V2%"
set "T3=%V3%"
set "T4=%V4%"
set "T5=%V5%"
set "T6=%V6%"
set "T7=%V7%"
set "T8=%V8%"
set "T9=%V9%"

set /a C=1

:loop
set /a Z%C%+=1
set "T%C%=!T%C%:~1!"
if not defined T%C% call :Conv
if %C%==10 goto :Ausgabe
goto :loop

:Ausgabe
echo %A1% %A2% %A3% %A4% %A5% %A6% %A7% %A8% %A9%>>output.raw

:Conv
if !Z%C%!==8 set A%C%=0.00000!V%C%:.=!
if !Z%C%!==9 set A%C%=0.0000!V%C%:.=!
if !Z%C%!==10 set A%C%=0.000!V%C%:.=!
if !Z%C%!==11 set A%C%=0.00!V%C%:.=!
set /a C+=1
goto :eof

Wie gesagt, mein File funktioniert, aber braucht eeeewig. Wie ihr sicher sehen könnt, ist es mir auch noch nicht gelungen Zählschleifen zu schreiben, die mehrere Variablen durchzählen sollen.

Ich hoffe ihr könnt mir helfen und freue mich über Antworten.
LG, snailgosh
 
Google mal verschachtelte Schleifen, ob batch oder Java usw. macht glaub keinen unterschied von der Logik her.

Was bedeutet für dich Langsam, kann sein das batch einfach sche** langsam ist.
 
Auch gut möglich, dass es mittels Powershell Code deutlich schneller läuft. Da hat man auch viel mehr Möglichkeiten und die Kontrolle darüber, wie der Code ausgeführt wird.

Ansonsten ist der Code halt echt viel zu komplex für diese simple Aufgabe. Aber ich weiß auch nicht, ob man das mit Batch wirklich einfacher machen kann.
 
Leider habe ich gerade wenig Zeit, aber vielleicht Hilft das ja.

Code:
for /f "skip=1 tokens=1-18 delims=. " %%a in (input.raw) do (
 Echo %%a%%b %%c%%d %%e%%f %%g%%h %%i%%j %%k%%l %%m%%n %%o%%p %%q%%r
 )

Das zerlegt dir deine Werte im input.raw in eine Variable vor dem dem Punkt und eine danach. So brauchst du nur die Anzahl der Zeichen der ersten (kurzen) Variable prüfen.
 
Ganz ehrlich... verwende hier was anderes als Batch.
Quick and dirty in C (dürfte was ASCII-Zahlen angeht mit zum schnellsten gehören)
Code:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]){

if (argc != 3) return EXIT_FAILURE;

double row[9];

FILE *input;
FILE *output;
int i;

char scratch[50];

input = fopen(argv[1], "r");
output = fopen(argv[2], "a");

fgets(scratch, 50, input);

while(9 == fscanf(input, "%lf %lf %lf %lf %lf %lf %lf %lf %lf", row, row+1, row+2, row+3, row+4, row+5, row+6, row+7, row+8))
    {
	    for(i=0; i<9; i++) {row[i] /= 1e6;}
		fprintf(output, "%.12f %.12f %.12f %.12f %.12f %.12f %.12f %.12f %.12f\n", row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
    }
    fclose(input);
	fclose(output);

return EXIT_SUCCESS;
}
 
Da alle Zielwerte kleiner als 1 sind, kann man das stark vereinfachen:

Code:
@echo off
:: InputFile
set InputFile=input.raw
:: OutputFile
set OutputFile=output.raw
		
setlocal enabledelayedexpansion

:: AusgabeDatei neu erstellen
echo. 2>%OutputFile%

for /f "skip=1 tokens=1-9 delims= " %%a in (%InputFile%) do (
  Call :format_digits %%a value[1]
  Call :format_digits %%b value[2]
  Call :format_digits %%c value[3]
  Call :format_digits %%d value[4]
  Call :format_digits %%e value[5]
  Call :format_digits %%f value[6]
  Call :format_digits %%g value[7]
  Call :format_digits %%h value[8]
  Call :format_digits %%i value[9]
  
  :: Werte schreiben
  Echo !value[1]! !value[2]! !value[3]! !value[4]! !value[5]! !value[6]! !value[7]! !value[8]! !value[9]! >> %OutputFile%
 )
goto :eof

:format_digits
set tmpNumber=%1
:: Dezimalpunkt entfernen
set tmpNumber=!tmpNumber:.=!
:: Nullen auffuellen
set tmpNumber=000000!tmpNumber!
:: Stellen auf 12 reduzieren und komplettieren
set tmpNumber=0.!tmpNumber:~-12!
set %~2=!tmpNumber!
goto :eof
 
Zuletzt bearbeitet: (Typo)
Mein Senf dazu: genau für so was hat damals Larry Wall die Programmiersprache Perl "erfunden", weil er meinte, dass so etwas mit einer Kombination aus bash, sed und awk zu umständlich ist. Daher: in Perl braucht man dafür nicht einmal ein Programm. Auf der Kommandozeile eingeben:
perl -lane 'print join "\t", map $_*0.001, @F if @F > 1' values.dat

das liefert hier dann das gewünschte Ergebnis (Werte in values.dat). Anstelle des join "\t", ... welches einen Tabulator zwischen die Werte setzt, kann man auch mit join " ", ... ein Leerzeichen verwenden.

Es gibt zwei einfache Arten, perl unter Windows zu haben:
a) git-bash installieren und dann mit Rechtsclick auf Verzeichnis im Explorer "Git Bash öffnen" wählen, oder
b) Windows Subsystem für Linux (z.B. Ubuntu) installieren

Wer sich das Leben ein klein wenig schwerer machen möchte, darf natürlich auch ein Python-Skript schreiben ;)
 
Oft hat man nicht die Möglichkeit, die Software zu installieren, mit der es am einfachsten geht ;)
 
Ich danke euch für eure Antworten, insbesondere euch, bauers und Andreas_, für eure cleveren Lösungsvorschläge.

Wie Andreas_ zuletzt richtig bemerkt hat, ist eine Installation von Software nicht immer möglich. Das Skript soll ohne weiteren Aufwand auf einer ganzen Reihe von Rechnern zum Einsatz kommen können.

Das andere Sprachen als Batch geeigneter für die Problemlösung wären, zweifele ich nicht an. ^^
 
Zurück
Oben