panguu
Goto Top

Schleife in Batch-Datei funktioniert nicht wie gewollt, bitte um Hilfestellung

Hallo miteinander,

ich verwende in einer Batch-Datei folgendes Schleifenkonstrukt:

:improcess
If Exist D:\test\*.pdf (
for %%f in ("D:\test\*.pdf") DO (
convert_program -option1 -option2 "%%f" D:\test\%date:~-2,2%%date:~-7,2%%date:~-10,2%_%time:~-11,2%%time:~-8,2%%time:~-5,2%%time:~-2,2%.tiff
)
)

Das bewirkt folgendes: es prüft das Verzeichnis D:\test auf vorhandene PDF-Dateien und falls dort welche vorhanden sind, werden diese mit einem extra Konvertierungsprogramm nach TIFF umgewandelt. Dabei generiere ich einen Dateinamen nach folgendem Schema:

131009_13184533.tiff

13 = aktuelles Jahr
10 = aktueller Monat
09 = heutiger Tag

13 = Uhrzeit/Stunden
18 = Uhrzeit/Minuten
45 = Uhrzeit/Sekunden
33 = Uhrzeit/Millisekunden

Ich habe die Millisekunden extra mitaufgenommen, weil ich verhindern wollte, dass Duplikate entstehen können. Aber das Problem ist, dass diese Schleife für alle generierten .TIFF Dateien dieselben Zeiten verwendet. Wenn ich z.B. in D:\test drei PDF-Dateien namens test1.pdf test2.pdf und test3.pdf liegen habe, dann generiert diese Schleife folgenden Output

131009_13213345.tiff

und zwar für alle 3 Dateien. Ich weiß das weil ich noch einen Zähler zum Testen genutzt habe und noch an den Dateinamen angefügt habe. Die %time% Variable scheint aber nur 1x eingelesen zu werden von der Schleife. Wie kann ich das verhindern und abändern, so daß Dateien entstehen nach diesem Muster:

131009_13213511.tiff (also um 13:21 Uhr und 35 Sekunden und 11 Millisekunden)
131009_13213869.tiff (also um 13:21 Uhr und 38 Sekunden und 69 Millisekunden)
131009_13214822.tiff (also um 13:21 Uhr und 48 Sekunden und 22 Millisekunden)

Bin für jeden Tip sehr dankbar.

Content-ID: 218884

Url: https://administrator.de/forum/schleife-in-batch-datei-funktioniert-nicht-wie-gewollt-bitte-um-hilfestellung-218884.html

Ausgedruckt am: 22.12.2024 um 08:12 Uhr

bastla
bastla 09.10.2013 um 16:54:43 Uhr
Goto Top
Hallo panguu!

Vorweg: (Batch-) Code liest sich besser mit passender Formatierung ...

Dein Stichwort wäre "delayedExpansion" - ungetestet etwa:
:improcess
for %%f in ("D:\test\*.pdf") DO (  
    setlocal enabledelayedexpansion    
    convert_program -option1 -option2 "%%f" D:\test\!date:~-2,2!!date:~-7,2!!date:~-10,2!_!time:~-11,2!!time:~-8,2!!time:~-5,2!!time:~-2,2!.tiff  
    endlocal
)
Die Prüfung per
If Exist D:\test\*.pdf (
kannst Du Dir sparen, da der "do"-Teil der Schleife ohnehin nur für vorhandene PDF-Dateien ausgeführt wird ...

Grüße
bastla
panguu
panguu 09.10.2013 um 16:59:05 Uhr
Goto Top
Hallo bastla,

leider funktioniert's auch mit "setlocal enabledelayedexpansion" nicht face-sad noch 'ne andre Idee?
bastla
bastla 09.10.2013 aktualisiert um 17:10:30 Uhr
Goto Top
Hallo panguu!

Was verstehst Du unter "funktioniert nicht"? Die Timestamps für die tiff-Dateinamen sollten auf jeden Fall passend erstellt werden ...

Anyhow - Du kannst es auch mit dieser Zeile (als Ersatz für die Zeilen 3 bis 5) versuchen:
call convert_program -option1 -option2 "%%f" D:\test\%%date:~-2,2%%%%date:~-7,2%%%%date:~-10,2%%_%%time:~-11,2%%%%time:~-8,2%%%%time:~-5,2%%%%time:~-2,2%%.tiff
Grüße
bastla
panguu
panguu 09.10.2013 um 17:21:53 Uhr
Goto Top
Auch mit "call" funktioniert es nicht. Schau mal, ich hänge im Dateinamen am Ende noch eine Ziffer mitdran, das ist ein ganz normaler Zähler.

set /a c=1
for %%f in ("D:\test\*.pdf") DO (  
 if not %errorlevel% == 0 goto :error
setlocal enabledelayedexpansion
call convert_program.exe -option1 -option2 "%%f" D:\test\%date:~-2,2%%date:~-7,2%%date:~-10,2%_%time:~-11,2%%time:~-8,2%%time:~-5,2%%time:~-2,2%_!c!.tiff  
                                      )
endlocal

Meine generierten Dateinamen lauten dann:

131009_17164533_1.tiff
131009_17164533_2.tiff
131009_17164533_3.tiff
131009_17164533_4.tiff

Verstehst du was ich nun meine?
bastla
bastla 09.10.2013 aktualisiert um 17:48:21 Uhr
Goto Top
Hallo panguu!

Kann ich trotzdem nicht nachvollziehen - bei mir sieht das so aus:
C:\Test>type MakeTIFF.cmd
@echo off & setlocal
for %%f in ("C:\test\*.pdf") DO (
    setlocal enabledelayedexpansion
    echo convert_program -option1 -option2 "%%f" C:\test\!date:~-2,2!!date:~-7,2
!!date:~-10,2!_!time:~-11,2!!time:~-8,2!!time:~-5,2!!time:~-2,2!.tiff
    ping -n 1 localhost >nul
    endlocal
)
C:\Test>MakeTIFF.cmd
convert_program -option1 -option2 "C:\test\1.pdf" C:\test\131009_17440514.tiff
convert_program -option1 -option2 "C:\test\2.pdf" C:\test\131009_17440532.tiff
convert_program -option1 -option2 "C:\test\3.pdf" C:\test\131009_17440546.tiff

C:\Test>
Du könntest es noch mit einem Unterprogramm versuchen:
:improcess
for %%f in ("D:\test\*.pdf") DO call :ProcessFile "%%f"  
goto :eof

:ProcessFile
convert_program -option1 -option2 %1 D:\test\%date:~-2,2%%date:~-7,2%%date:~-10,2%_%time:~-11,2%%time:~-8,2%%time:~-5,2%%time:~-2,2%.tiff
goto :eof
Grüße
bastla
panguu
panguu 10.10.2013 um 10:01:35 Uhr
Goto Top
dein oberes Beispiel funktioniert nur deswegen, weil du auch
ping -n 1 localhost >nul
verwendet hast. Wenn du das auskommentierst, dann wirst du dasselbe Ergebnis wie ich erhalten.

Also könnte ich durch diesen kleinen Workaround-Trick mit dem ping Befehl eine kleine Zeitverzögerung einbauen, das würde klappen, ja.
Danke dir hierfür. Auch wenn dadurch mein Problem behoben wurde, würde mich ordnungshalber trotzdem interessieren, warum das so innerhalb der Schleife abgearbeitet wird (also in einem Stück, zur exakt derselben Zeit).

Kennt ihr vielleicht noch eine elegantere/saubere Lösung zu diesem Phänomen?

Bastla, den unteren Teil habe ich mir jetzt gar nicht erst angeschaut mit den Unterprogrammen, da das obere ja bereits funktioniert hat. Trotzdem auch hierfür danke.

Grüße,
Pangu
bastla
bastla 10.10.2013 um 10:20:23 Uhr
Goto Top
Hallo panguu!
Wenn du das auskommentierst, dann wirst du dasselbe Ergebnis wie ich erhalten.
Mit dem "ping" wird ja nur die Zeit für den Programmablauf simuliert (der "Aufruf" besteht in meinem Beispiel ja nur aus einem "echo" und davon gehen sich in einer Hundertstelsekunde einige aus), um zeigen zu können, dass die Timestamp-Erstellung innerhalb der Schleife sehr wohl unterschiedliche Werte (Zeiten) ergibt.
warum das so innerhalb der Schleife abgearbeitet wird (also in einem Stück, zur exakt derselben Zeit).
In einem Stück abgearbeitet wird nur die Variablenauflösung (wenn nicht "delayed" wird). Vermutlich ist einfach Dein Programm sehr schnell ... face-wink

Grüße
bastla
panguu
panguu 10.10.2013 um 11:06:19 Uhr
Goto Top
Hallo bastla, ich hab gerade noch etwas herumexperimentiert. Wenn ich deinen obigen Code
C:\Test>type MakeTIFF.cmd 
@echo off & setlocal 
for %%f in ("C:\test\*.pdf") DO (   
    setlocal enabledelayedexpansion 
    echo convert_program -option1 -option2 "%%f" C:\test\!date:~-2,2!!date:~-7,2   
!!date:~-10,2!_!time:~-11,2!!time:~-8,2!!time:~-5,2!!time:~-2,2!.tiff 
    ping -n 1 localhost >nul 
    endlocal 
) 

betrachte, dann habe ich festgestellt, daß du statt %date% !date! verwendest, also statt dem Prozentzeichen (%) ein Ausrufezeichen (!). Und genau deswegen klappt es oder klappt es nicht. Es liegt also nicht wie vorhin von mir vermutet an dem "Ping"-Befehl, sondern ich hatte erstmal von dir abgeschrieben und ! verwendet. Und dann in meinem Code hatte ich wieder die Prozentzeichen drinstehen. Und beim Prozentzeichen scheint das enabledelayedexpansion nicht zu greifen. Ich habe also daraufhin den Ping-Befehl wieder gelöscht und verwende überall für meine date und time Variablen das Ausrufezeichen. Damit krieg ich nen Zeitstempel der einzelnen Datein mit 3 Millisekunden, das passt!

Was ist denn nun der Unterschied zwischen Prozentzeichen und Ausrufezeichen bei Variablen?
pieh-ejdsch
pieh-ejdsch 10.10.2013 um 12:27:23 Uhr
Goto Top
moin pangu,

wenn Du wärend der Schleifenabrbeitung eine Ausgabe in die Console erzeugst, könnte es auslangen diese Millisekunde zu überbrücken.

erster Test in der CMD Line wieviele Zeilen je Millisekunde
> cmd /von/c "for /l %i in (1 1 10000) do @(if !test! neq !time:~-2! echo %i !time:~-2!)&set "test=!time:~-2!""
1 34
15 35
220 36
437 37
654 38
872 39
1090 40
1306 41
1526 42
1745 43
1963 44
2185 45
2409 46
3879 52
4352 54
4575 55
4800 56
5025 57
5498 59
5723 60
5948 61
6172 62
6396 63
6621 64
6840 65
7563 68
7788 69
8011 70
8235 71
8459 72
8684 73
8907 74
9131 75
9355 76
9578 77
9799 78
Da nun hier auch eine Ausgabe erfolgt, aber die Millisekunde zum Unterschied nicht erreicht wird ist die Bearbeitung zu schnell.
Ein Wert geht sogar über 470 potentielle Zeilen, obwohl je zeile zwei Variablen dargestellt werden müssen und eine erstellt wird.
10000 zu 34 Millisekunden passt da auch noch nicht.
Eine Ausgabe reicht also nicht. Aber eine Ausgabe zu Dursuchen könnte dazu langen:
> cmd /von/c "for /l %i in (1 1 500) do @echo X|find "u" &(if !test! neq !time:~-2! echo %i  !time:~-2!) &set "test=!time:~-2!""|find /c /v ""
500
Da jetzt find (sogar ohne Ausgabe) etwas zu tun hat, verzögert das um ca 1 Millisekunde

Durch Verlegen der seperaten CMD instanz gibt es auch eine Verzögerung von je einer Millisekunde.
 type=plain>
> for /l %i in (1 1 20) do @cmd /von /c echo %i  !time:~-2!
1  22
2  23
3  24
4  25
5  26
6  28
7  29
8  30
9  31
10  32
11  33
12  34
13  35
14  36
15  37
16  38
17  39
18  40
19  41
20  42

Vllt ist die bessere Alternative eine Temporäre vbs zu schreiben, welche eine Millisekunde wartet.

Gruß Phil
bastla
bastla 10.10.2013 um 13:24:20 Uhr
Goto Top
Hallo panguu!
Was ist denn nun der Unterschied zwischen Prozentzeichen und Ausrufezeichen bei Variablen?
Falls ich das noch nicht erwähnt haben sollte: "delayedExpansion"

Schau Dir einmal das einschlägige Tutorial zur FOR-Schleife von Friemler an ...

Grüße
bastla
panguu
panguu 10.10.2013 aktualisiert um 15:09:24 Uhr
Goto Top
@phil, danke für deinen ausführlichen Beitrag. Jedoch habe ich durch Bastlas Hilfe herausgefunden, wo das ursprüngliche Problem war. "delayedExpansion" ist tatsächlich das richtige Schlagwort hierfür.

@bastla: Vielen herzlichen Dank für die Verlinkung dieses tollen Tutorials, das Friemler hier freundlicherweise zur Verfügung stellt. Sehr nettes Tutorial *daumen_Hoch!*. Da wird genau dieser Fall erörtert und beantwortet damit meine vorherige Frage zum Unterschied von Prozent- und Ausrufezeichen.

Durch ENABLEDELAYEDEXPANSION wird die verzögerte Variablenerweiterung aktiviert. Dadurch, dass ein Variablenname in Ausrufezeichen statt in Prozentzeichen eingeschlossen ist, wird dem Befehlsinterpreter mitgeteilt, diesen Variablennamen erst bei Ausführung des Befehls durch seinen Wert zu ersetzen, der durch den vorhergehenden SET-Befehl gesetzt wurde

Vielen Dank! Problem wurde als gelöst markiert.