Batch - mögliche Codeoptimierung?
Hi,
ich habe eine kleine Batch geschrieben, die rudimentäre Sortieraufgaben übernimmt. Meine BATCH-Erfahrungen sind leider noch überschaubar.
FRAGE: ist es möglich den folgenden Code so zu optimieren, dass die Batch schneller arbeitet?
mir is aufgefallen, dass seit ich mit Sprungmarken arbeite die Scripe langsamer laufen als ohne.
Mit Tokens und Delims komm ich der Sache leider nicht bei. Wenn ich die Sprungmarke rausnehme habe ich das Problem, dass in die Variablen in der Schleife nicht gehen. Die Variable brauch ich aber für die Sringmanupulation.
Ich sortiere mit dem Script ca. 10.000 Files - das dauert leider ewig. Der Code hier hat zB. wesentlich schneller gearbeitet:
Gibt es eine Möglichkeit den Code von oben so zu optimieren, dass das Script schneller arbeitet? Oder muss man dann direkt auf VBS oder ähnliches umsteigen?
Danke und vg,
ich habe eine kleine Batch geschrieben, die rudimentäre Sortieraufgaben übernimmt. Meine BATCH-Erfahrungen sind leider noch überschaubar.
FRAGE: ist es möglich den folgenden Code so zu optimieren, dass die Batch schneller arbeitet?
@echo off
set "MaskSort=*.jpg
for /F "delims=" %%i in ('dir/b %MaskSort%') do set "Name=%%~ni" & call :ProcessFile "%%i"
echo Sortiervorgang beendet.
goto :eof
:ProcessFile
if exist "%Name:~,-4%" (
move "%name%%~x1" "%Name:~,-4%\" 2>NUL
) ELSE (
echo Erstelle Ordner : %Name:~,-4%
md "%Name:~,-4%" 2>NUL & move "%name%%~x1" "%Name:~,-4%\" 2>NUL
)
)
mir is aufgefallen, dass seit ich mit Sprungmarken arbeite die Scripe langsamer laufen als ohne.
Mit Tokens und Delims komm ich der Sache leider nicht bei. Wenn ich die Sprungmarke rausnehme habe ich das Problem, dass in die Variablen in der Schleife nicht gehen. Die Variable brauch ich aber für die Sringmanupulation.
Ich sortiere mit dem Script ca. 10.000 Files - das dauert leider ewig. Der Code hier hat zB. wesentlich schneller gearbeitet:
for /F "tokens=2 delims=-" %%i in ('dir/b') do (
if exist "%%~ni" (
move "*%%~ni.*" "%%~ni\" 2>NUL
) ELSE (
echo Erstelle Ordner : %%~dpni
md "%%~ni" 2>NUL
move "*%%~ni.*" "%%~ni\" 2>NUL
)
)
Gibt es eine Möglichkeit den Code von oben so zu optimieren, dass das Script schneller arbeitet? Oder muss man dann direkt auf VBS oder ähnliches umsteigen?
Danke und vg,
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 160957
Url: https://administrator.de/contentid/160957
Ausgedruckt am: 25.11.2024 um 00:11 Uhr
21 Kommentare
Neuester Kommentar
Hallo evotoy!
Soferne es keine Namen mit enthaltenen "!" gibt, könntest Du es so versuchen (ungetestet):
So wird auch nur eine Stringzerlegung (und keine Abfrage ) benötigt.
Grüße
bastla
Soferne es keine Namen mit enthaltenen "!" gibt, könntest Du es so versuchen (ungetestet):
@echo off & setlocal enabledelayedexpansion
set "MaskSort=*.jpg
for /F "delims=" %%i in ('dir/b /a-d %MaskSort%') do (
set "Name=%%~ni"
set "Name=!Name:~,-4!"
md "!Name!" 2>nul
move "%%i" "!Name!\"
)
echo Sortiervorgang beendet.
Grüße
bastla
moin evotoy,
schneller als das, was bastla als lösung gepostet hat wirst Du es nicht mehr mit batch bekommen. Das mag daran liegen, das eine Variable (2mal) erst gesetzt wird und auch wieder aufgelöst wird. Das kostet Zeit.
was Du noch überprüfen kannst:
Bei Batches mit Sprungmarken bzw. generell Batches - Ist im Online-Virenscanner die Batch in den Ausnahmen deklariert.
Gruß Phil
mir is aufgefallen, dass seit ich mit Sprungmarken arbeite die Scripe langsamer laufen als ohne.
...
Gibt es eine Möglichkeit den Code von oben so zu optimieren, dass das Script schneller arbeitet? Oder muss man dann direkt auf VBS oder ähnliches umsteigen?
...
Gibt es eine Möglichkeit den Code von oben so zu optimieren, dass das Script schneller arbeitet? Oder muss man dann direkt auf VBS oder ähnliches umsteigen?
schneller als das, was bastla als lösung gepostet hat wirst Du es nicht mehr mit batch bekommen. Das mag daran liegen, das eine Variable (2mal) erst gesetzt wird und auch wieder aufgelöst wird. Das kostet Zeit.
was Du noch überprüfen kannst:
Bei Batches mit Sprungmarken bzw. generell Batches - Ist im Online-Virenscanner die Batch in den Ausnahmen deklariert.
Gruß Phil
Na ja, pieh-ejdsch,
diese Antwort ist mir zu technisch...
Eine "Optimierung eines Ablaufs" ist doch nicht nur "benutze ich eine oder zwei Stringzerlegungen". Oder ein goto oder verzögerte Variablen.
Bei den oben beschriebenen 10000 zu verteilenden *.jpgs kommt es sicher eher auf die (vorhersagbare) Verteilung in einzelne Ordner an.
Wenn beispielsweise der obige Batch läuft und 10000 Dateien werden in 10000 Ordner verschoben von denen 9999 neu angelegt werden und einer vorher existiert...
Dann ist es die "passende" Lösung.
Wenn allerdings die 10000 Dateien in nur drei Ordner verschoben/verteilt werden sollen, die auch alle vorher existieren...
-> dann würde sicherlich ärgerlich viel Zeit damit verbraten, einfach nur das überflüssige "md "!Name!" 2>nul" abzuwarten.
In dem unterem Szenario wäre es eleganter, nicht die Dateien einzeln abzuklappern, sondern die bestehenden Zielordner.
Und die Dateien auch mit Wildcards en bloc zu verschieben.
Oder drei Parallel-Threads für die drei Ordner loszujagen...
Aber da kann man/frau nur ansetzen, wenn denn dieses Sortierkrams a) regelmäßig und b) mit vorhersagbarer Ausgangssituation stattfindet.
Grüße
Biber
diese Antwort ist mir zu technisch...
Eine "Optimierung eines Ablaufs" ist doch nicht nur "benutze ich eine oder zwei Stringzerlegungen". Oder ein goto oder verzögerte Variablen.
Bei den oben beschriebenen 10000 zu verteilenden *.jpgs kommt es sicher eher auf die (vorhersagbare) Verteilung in einzelne Ordner an.
Wenn beispielsweise der obige Batch läuft und 10000 Dateien werden in 10000 Ordner verschoben von denen 9999 neu angelegt werden und einer vorher existiert...
Dann ist es die "passende" Lösung.
Wenn allerdings die 10000 Dateien in nur drei Ordner verschoben/verteilt werden sollen, die auch alle vorher existieren...
-> dann würde sicherlich ärgerlich viel Zeit damit verbraten, einfach nur das überflüssige "md "!Name!" 2>nul" abzuwarten.
In dem unterem Szenario wäre es eleganter, nicht die Dateien einzeln abzuklappern, sondern die bestehenden Zielordner.
Und die Dateien auch mit Wildcards en bloc zu verschieben.
Oder drei Parallel-Threads für die drei Ordner loszujagen...
Aber da kann man/frau nur ansetzen, wenn denn dieses Sortierkrams a) regelmäßig und b) mit vorhersagbarer Ausgangssituation stattfindet.
Grüße
Biber
@ph
Nach einem kurzen Test (mit nur einer Zählschleife mit 30000 Durchläufen und einem "
Der Unterschied lag bei etwa 5 % ...
Grüße
bastla
[Edit] @Biber
[/Edit]
Nach einem kurzen Test (mit nur einer Zählschleife mit 30000 Durchläufen und einem "
echo
" der beiden Befehle) könnte es tatsächlich effizienter sein, nur eine einmalige Variablenzuweisung und dafür die zweimalige Teilstringbildung zu verwenden - als Schleifeninhalt daher: set "Name=%%~ni"
md "!Name:~,-4!" 2>nul
move "%%i" "!Name:~,-4!\"
Grüße
bastla
[Edit] @Biber
"Optimierung eines Ablaufs"
wäre dann vermutlich das Thema des nächsten Threads geworden ... [/Edit]
diese Antwort ist mir zu technisch...
wohl eher auch noch zu Allgemein gehalten.In dem unterem Szenario wäre es eleganter, nicht die Dateien einzeln abzuklappern, sondern die bestehenenden Zielordner.
Und die Dateien auch mit Wildcards en bloc zu verschieben.
das wäre dann die Option für den ersten Teil des Scriptes, damit im zweiten Teil nicht soviel ["md Ordner" aber ohne Fehlermeldung] durchgeführt werden.Und die Dateien auch mit Wildcards en bloc zu verschieben.
@bastla hast Du Die Ausgabe Weggeleitet?
da das Auflösen einer Variable etwas länger dauert als das setzen - dürfte, wenn ich mit meiner Theorie nicht falsch liege, die mindest-zweimalige Auflösung dieser Variable als Laufvariable noch einen Zacken schneller sein als das Direkte Auflösen der Variable.
ist ein "if not exist Ordner md Ordner" nicht schneller als ein "md Ordner 2>nul"
Gruß Phil
Zitat von @bastla:
Hallo evotoy!
Soferne es keine Namen mit enthaltenen "!" gibt, könntest Du es so versuchen (ungetestet):
Hallo evotoy!
Soferne es keine Namen mit enthaltenen "!" gibt, könntest Du es so versuchen (ungetestet):
Damit es auch mit dem bösen "!" klappt, kann man einfach den Block noch ein bisschen mit Setlocal und Endlocal würzen.
@echo off
setlocal DisableDelayedExpansion
set "MaskSort=*.jpg
for /F "tokens=* delims=" %%i in ('dir/b /a-d %MaskSort%') do (
set "Name=%%~ni"
set "OrgName=%%~ni"
setlocal EnableDelayedExpansion
set "Name=!Name:~,-4!"
md "!Name!"
move "!OrgName!" "!Name!\"
EndLocal
) 2>nul
echo Sortiervorgang beendet.
Und die Kombination "Tokens=* delims=" entspricht von der Ausgabe "delims=" ist aber schneller (abhängig von den Stringlängen).
Gruß
jeb
moin jeb,
bei beiden oder nur bei "delims=" ?
versucht die Forschleife etwa erst den ganzen Sting in viele Tokens (welche ja nur eines sind) zu zerlegen und dann werden diese wieder zusammengesetzt?
sonst müsste es ja keinen messbaren Unterschied geben.
Gruß Phil
Und die Kombination "Tokens=* delims=" entspricht von der Ausgabe "delims=" ist aber schneller (abhängig von den Stringlängen).
wie meinst Du abhängig?bei beiden oder nur bei "delims=" ?
versucht die Forschleife etwa erst den ganzen Sting in viele Tokens (welche ja nur eines sind) zu zerlegen und dann werden diese wieder zusammengesetzt?
sonst müsste es ja keinen messbaren Unterschied geben.
Gruß Phil
Wenn wir hier ohnehin alle durcheinander rumirrlichtern, ohne den TO abzuwarten...
... einen habe ich auch noch...
Wozu denn jetzt blind irgendwelche Perlen/Ausrufezeichen/in Tränen aufgelösten Variablen in die Nacht/vor die Säue/durchs Dorf werfen/treiben?
Menno, früher haben wir die Menschen darauf hingewiesen, dass Bätche sogar unbeaufsichtigt laufen können, wenn sie sauber geschrotet sind.
Who cares denn, ob das Verschieben von 10000 Dateien 10 Minuten oder 45 Minuten dauert?
Wenn ich den Windows-Explorer damit losjage und der mir seine fliegenden Datenklumpen hinmalt, dann dauert es prognostiziert zwischen 45 und 7865 Minuten und er ist je nach Laune zu 3% ich korrigiere 44% ich korrigiere 9% ich korrigiere 144% fertig...
5 % Laufzeitoptimierung bei einem Batch.... dafür steh ich nicht nachts auf...
Grüße
Biber
... einen habe ich auch noch...
for /l %%a in (1,1,30000) do if not exist R:\bla md R:\bla 1003 ms
for /l %%a in (1,1,30000) do md R:\bla 2>nul 4445 ms
for /l %%a in (1,1,30000) do md R:\bla 2>nul 4445 ms
Wozu denn jetzt blind irgendwelche Perlen/Ausrufezeichen/in Tränen aufgelösten Variablen in die Nacht/vor die Säue/durchs Dorf werfen/treiben?
Menno, früher haben wir die Menschen darauf hingewiesen, dass Bätche sogar unbeaufsichtigt laufen können, wenn sie sauber geschrotet sind.
Who cares denn, ob das Verschieben von 10000 Dateien 10 Minuten oder 45 Minuten dauert?
Wenn ich den Windows-Explorer damit losjage und der mir seine fliegenden Datenklumpen hinmalt, dann dauert es prognostiziert zwischen 45 und 7865 Minuten und er ist je nach Laune zu 3% ich korrigiere 44% ich korrigiere 9% ich korrigiere 144% fertig...
5 % Laufzeitoptimierung bei einem Batch.... dafür steh ich nicht nachts auf...
Grüße
Biber
Zitat von @Biber:
Wenn ich den Windows-Explorer damit losjage und der mir seine fliegenden Datenklumpen hinmalt, dann dauert es prognostiziert
zwischen 45 und 7865 Minuten und er ist je nach Laune zu 3% ich korrigiere 44% ich korrigiere 9% ich korrigiere 144% fertig...
5 % Laufzeitoptimierung bei einem Batch.... dafür steh ich nicht nachts auf...
Wenn ich den Windows-Explorer damit losjage und der mir seine fliegenden Datenklumpen hinmalt, dann dauert es prognostiziert
zwischen 45 und 7865 Minuten und er ist je nach Laune zu 3% ich korrigiere 44% ich korrigiere 9% ich korrigiere 144% fertig...
5 % Laufzeitoptimierung bei einem Batch.... dafür steh ich nicht nachts auf...
Wie recht er hat!
tokens=* ist schneller als delims=, macht aber nunmal auch was anderes, schluckt so nebenbei am Anfang alle Spaces und Tabs.
Zusammen sind sie stark und schnell.
Allerdings nur wenn die Daten auch lang sind, bei kurzen Strings oder hier dem Dateiname, geht der Unterschied so ziemlich gegen 0,0%.
Bei langen Strings wird es dann aber immer größer, so emotional gefühlte 50%-200%. (Ab 1000Zeichen ++).
Vermutlich hier nicht ganz so relevant, ausser die Dateinamen wären überraschend lang.
Das Verschieben der Dateien dürfte allerdings bereits beendet sein, während hier noch über die schnellste Lösung debattiert wird.
Grüße
jeb
Hallo evotoy!
Vermutlich wird's dann die Kombination bringen - etwa:
[Edit] Überzähligen "*" aus "
Dein gesuchtes Suchwort ist übrigens "delayedExpansion" ...
Grüße
bastla
Vermutlich wird's dann die Kombination bringen - etwa:
@echo off & setlocal
set "MaskSort=*.jpg"
for /d %%i in (*) do move "%%i%MaskSort%" "%%i"
for /F "tokens=* delims=" %%i in ('dir/b /a-d %MaskSort%') do (
set "Name=%%~ni"
set "OrgName=%%~ni"
setlocal EnableDelayedExpansion
set "Name=!Name:~,-4!"
if not exist "!Name!" md "!Name!"
move "!OrgName!" "!Name!\"
endlocal
)
echo Sortiervorgang beendet.
move
"-Quelle entfernt [/Edit]Dein gesuchtes Suchwort ist übrigens "delayedExpansion" ...
Grüße
bastla
@bastla
Muss es in Zeile 3 nicht statt "...move "%%i*%MaskSort%" besser lauten "...move "%%i\%MaskSort%" ?
Nein, Unsinn...
Wenn schon, dann
Beispiel:
Grüße
Biber
Nein, Unsinn...
Wenn schon, dann
...
Set "SortMask=.jpg"
for /d %%i in (*) do @echo move "*%%i%Sortmask%" "%%i\"
...
>for /d %i in (*) do @echo move "*%i.jpg" "%i\"
move "*logs.jpg" "logs\"
Grüße
Biber
@Biber
Da aus dem aktuellen Ordner in dessen entsprechende Unterordner verschoben werden soll, sollte das so schon passen - Beispiel: In den Unterordner "Bilder105" sollten alle "Bilder105????.jpg" verschoben werden (wobei die Schreibweise mit "*" zugegeben etwas weniger genau ist) ...
[Edit] Da "*" ja schon in %Maskort% enthalten ist, ginge es ja auch gar nicht mit "????" - allerdings kann er dann auch in der Quellangabe eingespart werden [/Edit]
Grüße
bastla
Da aus dem aktuellen Ordner in dessen entsprechende Unterordner verschoben werden soll, sollte das so schon passen - Beispiel: In den Unterordner "Bilder105" sollten alle "Bilder105????.jpg" verschoben werden (wobei die Schreibweise mit "*" zugegeben etwas weniger genau ist) ...
[Edit] Da "*" ja schon in %Maskort% enthalten ist, ginge es ja auch gar nicht mit "????" - allerdings kann er dann auch in der Quellangabe eingespart werden [/Edit]
Grüße
bastla
moin,
noch ne andere Strategie mit Liste (ungetestet)
[Edit] beim DEL "2>nul" entfernt und stattdessen if exist eingefügt
findstr Suchzeichenfolge nochmal angepasst
beim MOVE 4 Platzhalter eingesetzt statt ein Stern (sonst gehts in die Hose bei mehreren Namenlängen und gleichen anfang
[/Edit]
Gruß Phil
noch ne andere Strategie mit Liste (ungetestet)
::----snipp----MoveTo0,-4Folder.cmd
@echo Off
set Woher="D:\ein Verzeichnis"
set "MaskSort=*.jpg"
pushD %Woher%
if exist "%temp%\Dirtmp2" del "%temp%\Dirtmp2"
:Anfang
if exist "%temp%\Dirtmp" del "%temp%\Dirtmp"
if exist "%temp%\Dirtmp2" (move "%temp%\Dirtmp2" "%temp%\Dirtmp">nul ) else dir /b %MaskSort%>"%temp%\Dirtmp"||(popD&goto :eof)
set /p Name=<"%temp%\Dirtmp"
if not exist "%Name:~,-4%" md "%Name:~,-4%"
move "%Name:~,-4%????%MaskSort:~-4%" "Name:~,-4%"
findstr /i /v /b "%Name:~,-4%....%Masksort:~-4%" "%temp%\Dirtmp">"%temp%\Dirtmp2"
goto :Anfang
::----snapp----MoveTo0,-4Folder.cmd
[Edit] beim DEL "2>nul" entfernt und stattdessen if exist eingefügt
findstr Suchzeichenfolge nochmal angepasst
beim MOVE 4 Platzhalter eingesetzt statt ein Stern (sonst gehts in die Hose bei mehreren Namenlängen und gleichen anfang
[/Edit]
Gruß Phil