misterjo
Goto Top

Zippen von Dateien in Variablen Verzeichnissen - geschachtelte FOR-Schleife

Hallo zusammen,

Das ist mein erster Eintrag hier. Ich hoffe, dass ihr mir helfen könnt.

Ich habe folgende Ausgangssituation:
Stammverzeichnis: D:\Temp

Darunter gibt es folgende Verzeichnisstruktur (Namen sind Variabel und beinhalten Leerzeichen):
Cat 1
Cat 2
Cat 3
usw.

In diesen Verzeichnissen werden zyklisch neue Textdateien abgelegt mit ebenfalls variable Namen mit Leerzeichen.

Ich möchte per Skript die Textdateien in eine Zip-Datei verschieben. Die Zip-Datei liegt unter bzw. heist: d:\<Jahr>\<Monat>\<Jahr>-<Verzeichnisname>.zip

Hierzu habe ich mir folgendes Skript überlegt:

:datum in Variablen
set "Jahr=%date:~-4%"
set "Monat=%date:~-7,2%"
set "Tag=%date:~-10,2%"

: Schleife über alle Unterverzeichnisse in D:\Temp
for /f "tokens=*" %%i in ('dir /b d:\Temp') do (
set "cat=%%i"
echo %cat%
: Schleife über alle Dateien im Unterverzeichnis
for /R "d:\Temp\%cat%" %%j in (*.txt) do (
set "Report=%%j"
echo %Report%
: erst mal wird nur hinzugefügt und nicht verschoben. 7zip kann nicht moven, d.h. das Ergebnis ist hier noch zu prüfen und bei Erfolg ist %Report% zu löschen. Kommt später.
"%programfiles%\7-zip\7z.exe" a "D:\%Jahr%\%Monat%\%Jahr%-%cat%.zip" "%Report%"

)
)

Das funktioniert nur für den ersten Schleifendurchlauf. Danach haben die Variablen %cat% und %Report% feste Werte, die nicht mehr überschrieben werden.
1. Durchlauf der äußeren Schleife:
%%i == Cat 3
echo %cat% ergibt "Cat 3"

2. Durchlauf der äußeren Schleife:
%%i == Cat 2
jedoch
echo %cat% ergibt immer noch "Cat 3"

3. Durchlauf und alle weiteren Durchläufe, sowie bei der inneren Schleife passiert dasselbe mit dem Ergebnis, dass x mal die gleiche Textdatei in die gleiche Zip-Datei gezippt wird.

Ich habe schon rauf und runter gegooglet, aber nichts brauchbares gefunden. Es ware super, wenn mir hier jemand weiterhelfen könnte.

Ich danke euch schonmal für eure Antworten!

Viele Grüße
Misterjo

Content-Key: 285545

Url: https://administrator.de/contentid/285545

Printed on: April 24, 2024 at 20:04 o'clock

Member: rubberman
Solution rubberman Oct 14, 2015, updated at Oct 15, 2015 at 19:01:42 (UTC)
Goto Top
Hallo misterjo, willkommen im Forum.

Variablen werden in einer Kommandozeile oder einem in Klammern eingefassten Block von Kommandozeilen nur einmal zum Wert expandiert. Das passiert noch bevor die Zeile/der Block ausgeführt wird. Der Rumpf deiner FOR Schleifen ist so ein Block. Abhilfe würde die verzögerte Variablenerweiterung schaffen (setlocal EnableDeleyedExpansion), wobei die % einer Variablen durch ! ersetzt werden würden. Die Verarbeitung ist aber trotzdem nicht einfach, da nun ein ! in einem String (bspw. ein Dateiname) zu Fehlinterpretationen führen würde.

In deinem Fall stellt sich die Frage, warum du überhaupt die Variablen cat und Report definierst. Ebenso gut kannst du innerhalb des Schleifenkonstrukts mit den FOR Variablen %%i und %%j weiterarbeiten.

Grüße
rubberman
Member: misterjo
misterjo Oct 15, 2015 at 06:36:01 (UTC)
Goto Top
Hallo rubberman,

Dankeschön für die schnelle Antwort. Mit DelayedExpansion hatte ich auch schon rumexperimentiert, aber das geht vollständig schief, weil !cat! innerhalb des Strings der for /R anscheinend nicht aufgelöst wird, d.h.
for /R "d:\Temp\!cat!" %%j in (*.txt) do ... liefert keinen Treffer, da es das Verzeichnis !cat! nicht gibt.

Deinen Vorschlag die Schleifenvariablen %%i und %%j direkt zu verwenden habe ausprobiert. Leider funktioniert es nicht. %%i wird wieder in
for /R "d:\Temp\%%i" ... nicht aufgelöst. Aus %%i wird bei der Auflösung ein %i, was wiederum als Verzeichnis nicht vorhanden ist und somit keinen Treffer liefert.
Das Übel scheint eine fehlende (späte) Variablenauflösung in der Pfadangabe der for /R zu sein. Ein %cat% wurde beim Lesen des Skriptes aufgelöst und war zur Laufzeit fest und damit kein Problem. Wäre es eine Lösung die for /R durch eine for /f auszutauschen? Kann mir jemand die Syntax einer equivalenten for /f nennen? Genügt da "tokens=*" oder muss bzw. sollte da mehr rein?

Hier ist der Quelltext:

:datum in Variablen
set "Jahr=%date:~-4%"
set "Monat=%date:~-7,2%"
set "Tag=%date:~-10,2%"

: Schleife über alle Unterverzeichnisse in D:\Temp
for /f "tokens=*" %%i in ('dir /b d:\Temp') do (
echo %%i
: Schleife über alle Dateien im Unterverzeichnis
for /R "d:\Temp\%%i" %%j in (*.txt) do (
echo %%j
"%programfiles%\7-zip\7z.exe" a "D:\%Jahr%\%Monat%\%Jahr%-%%i.zip" "%%j"
)
)

und hier das Ergebnis:

D:\>set "Jahr=2015"

D:\>set "Monat=10"

D:\>set "Tag=15"

D:\>for /F "tokens=*" %i in ('dir /b d:\Temp') do (
echo %i
for /R "d:\Temp\%i" %j in (*.txt) do (
echo %j
"C:\Program Files\7-zip\7z.exe" a "D:\2015\10\2015-%i.zip" "%j"
)
)

D:\>(
echo Cat 1
for /R "d:\Temp\%i" %j in (*.txt) do (
echo %j
"C:\Program Files\7-zip\7z.exe" a "D:\2015\10\2015-Cat 1.zip" "%j"
)
)
Cat 1

D:\>(
echo Cat 2
for /R "d:\Temp\%i" %j in (*.txt) do (
echo %j
"C:\Program Files\7-zip\7z.exe" a "D:\2015\10\2015-Cat 2.zip" "%j"
)
)
Cat 2

D:\>(
echo Cat 3
for /R "d:\Temp\%i" %j in (*.txt) do (
echo %j
"C:\Program Files\7-zip\7z.exe" a "D:\2015\10\2015-Cat 3.zip" "%j"
)
)
Cat 3

Viele Grüße
misterjo
Member: misterjo
misterjo Oct 15, 2015 at 06:55:46 (UTC)
Goto Top
jetzt kommentiere ich meinen eigenen Kommentar...

der folgenden Quelltext funktioniert (Dank an rubberman für die zündende Idee!):

:datum in Variablen
set "Jahr=%date:~-4%"
set "Monat=%date:~-7,2%"
set "Tag=%date:~-10,2%"

: Schleife über alle Unterverzeichnisse in D:\Temp
for /f "tokens=*" %%i in ('dir /b d:\Temp') do (
echo %%i
: Schleife über alle Dateien im Unterverzeichnis
for /f "tokens=*" %%j in ('dir /b "d:\Temp\%%i"') do (
echo %%j
"%programfiles%\7-zip\7z.exe" a "D:\%Jahr%\%Monat%\%Jahr%-%%i.zip" "d:\Temp\%%i\%%j"
)
)

Jetzt habe ich nur noch die Frage, ob for /f "tokens=*" genügt oder ob for /f mehr Optionen benötigt um auch mit ungewöhnlichen Dateinamen klar zu kommen.

Der vollständigkeithalber lasse ich den Thread noch offen bis ich die Ergebnisprüfung des 7zip und das Löschen der gezippten Dateien laufen habe und poste dann das finale Skript. Wenn jemand eine Idee zur Fehlerprüfung hat, wäre ich dafür dankbar. Im Moment würde ich versuchen die Ausgabe des 7zip zu parsen ... Geht das vielleicht auch einfacher?

Viele Grüße
misterjo
Member: rubberman
Solution rubberman Oct 15, 2015 updated at 19:01:51 (UTC)
Goto Top
Hallo misterjo.

Jetzt habe ich nur noch die Frage, ob for /f "tokens=*" genügt
Ja, genügt. "delims=" wäre die Alternative zu diesem Zweck, das Ergebnis ist aber (in diesem Fall) dasselbe.
Im Moment würde ich versuchen die Ausgabe des 7zip zu parsen ... Geht das vielleicht auch einfacher?
Hmm. Habe 7zip noch nicht in der Kommandozeile benutzt. Aber laut Referenz kannst du den Rückgabewert abfragen.
"%programfiles%\7-zip\7z.exe" a "D:\%Jahr%\%Monat%\%Jahr%-%%i.zip" "d:\Temp\%%i\%%j"   
if errorlevel 1 echo Fehler.

... wobei if errorlevel 1, im Gegensatz zur Prüfung der %errorlevel% Variable, auch in einem in Klammern gesetzten Zeilenblock funktioniert. Die Bedeutung ist: "Wenn der Rückgabewert größer oder gleich 1 ist, dann ..."

Grüße
rubberman
Member: misterjo
misterjo Oct 15, 2015 at 19:00:28 (UTC)
Goto Top
Hallo rubberman,

Danke für deine Hilfe. Ich habe die Fehlerprüfung und das Löschen der Quelldateien in das Skript eingebaut. Es läuft super!
Desweiteren habe ich die Logausgabe minimiert und in eine Datei umgelenkt und das Quell- und Ziel-Verzeichnis, sowie die Log-Datei in Variablen abgelegt.
Das Löschen der Dateien könnte man noch mit einem del /f verschärfen, aber das ist bei mir nicht notwendig.

Hier ist das fertige Skript für alle Interessierten:

echo off

:datum in Variablen
set "Jahr=%date:~-4%"
set "Monat=%date:~-7,2%"
rem set "Tag=%date:~-10,2%"

set Source=D:\Temp
set Dest=D:\%Jahr%\%Monat%
set Log=D:\MoveAndZipFiles.log


: Schleife über alle Unterverzeichnisse in D:\Temp
for /f "tokens=*" %%i in ('dir /b %Source%') do (

: Schleife über alle Dateien im Unterverzeichnis
for /f "tokens=*" %%j in ('dir /b "%Source%\%%i"') do (

"%programfiles%\7-zip\7z.exe" a "%Dest%\%Jahr%-%%i.zip" "%Source%\%%i\%%j" > nul
if errorlevel 1 (
set "ErrorFile=%Source%\%%i\%%j"
goto Error
)

: File löschen
del "%Source%\%%i\%%j"

echo "%Source%\%%i\%%j gezippt und lokal gelöscht" >> %Log%
)
)
goto Finish

:Error
echo "Es ist ein Error beim zippen aufgetreten, Datei: %ErrorFile% - Abbruch" >> %Log%
goto Finish

:Finish


Vielen Dank für die Hilfe!
Grüße
misterjo