Dateien kopieren, rekursiv in einen Ordner, Dubletten durchnummerieren.
auf die Gefahr hin, daß mich der Biber gleich anknappert:
Ich weis, kopieren und umbenennen ist schon oft behandelt, aber ich bekomme die Mischung nicht hin.
Erreichen möchte ich, das alle Files aus beliebig tiefen Unterverzeichnisse von %parent% in ein %target% kopiert werden. Dubletten sollen dabei nicht überschrieben, sondern durchnummeriert werden. Die Baumstruktur von %parent% soll aufgelöst werden (keine SubDirs in %target%
Ich habe folgende Skripte versucht zu kombinieren:
::-----Inhalt ftpcopy.bat
::--- MoveAll2OneDir.bat (ungetestete Skizze)
Mein Versuch:
:: --- MoveAll2OneDir.bat (ungetestete Skizze)
:: @echo off & setlocal
Set parent=s:\test\
Set target=s:\target\
Pushd "%parent%" && Rem In das parent Verzeichnis wechseln
for /F %%i in ('dir /a:D /b') do (
for /F %%a in ('dir /b /A:-d %%i\*.*') do (
if exist %target%%%a (
if exist %target%%%a-4 (echo "Worst-Case war nicht worst genug!") && pause
if exist %target%%%a-4 goto end
if exist %target%%%a-3 rename %Target%%%a-3 %%a-4
if exist %target%%%a-2 rename %Target%%%a-2 %%a-3
if exist %target%%%a-1 rename %Target%%%a-1 %%a-2
rename %target%%%a %%a-1
)
copy %parent%%i%%a% %target%%a% >nul
)
)
::del %inputdir%%filename%
Popd && rem ..und alten Zustand von Lw/Verz wiederherstellen... ist eine Stilfrage
::--- MoveAll2OneDir.bat
scheitert daran, daß der copy-Befehl irgendwie nicht richtig ist:
Datei nicht gefunden
S:\test>copy s:\test\ s:\target\ 1>nul
Das System kann die angegebene Datei nicht finden.
Irgendwie schaut %%a aber doch gefüllt zu werden, irgendwo im Output steckt ein
S:\test>(if exist s:\emese_target\install.txt ( ...
Nun bin ich in Batch-Proggen absoluter Neuling, mir geht es eigentlich nur um mein Kopier-Problem. Vor allem die Variablen-Deklarierung versteh ich gar nicht. Vielleicht erbarmt sich jemand und richtet mal mein Skript. Und vielleicht bekommt er die Nummerierung auch an den Dateinamen, und nicht an den File-Typ.
Danke
Ich weis, kopieren und umbenennen ist schon oft behandelt, aber ich bekomme die Mischung nicht hin.
Erreichen möchte ich, das alle Files aus beliebig tiefen Unterverzeichnisse von %parent% in ein %target% kopiert werden. Dubletten sollen dabei nicht überschrieben, sondern durchnummeriert werden. Die Baumstruktur von %parent% soll aufgelöst werden (keine SubDirs in %target%
Ich habe folgende Skripte versucht zu kombinieren:
::-----Inhalt ftpcopy.bat
::--- MoveAll2OneDir.bat (ungetestete Skizze)
Mein Versuch:
:: --- MoveAll2OneDir.bat (ungetestete Skizze)
:: @echo off & setlocal
Set parent=s:\test\
Set target=s:\target\
Pushd "%parent%" && Rem In das parent Verzeichnis wechseln
for /F %%i in ('dir /a:D /b') do (
for /F %%a in ('dir /b /A:-d %%i\*.*') do (
if exist %target%%%a (
if exist %target%%%a-4 (echo "Worst-Case war nicht worst genug!") && pause
if exist %target%%%a-4 goto end
if exist %target%%%a-3 rename %Target%%%a-3 %%a-4
if exist %target%%%a-2 rename %Target%%%a-2 %%a-3
if exist %target%%%a-1 rename %Target%%%a-1 %%a-2
rename %target%%%a %%a-1
)
copy %parent%%i%%a% %target%%a% >nul
)
)
::del %inputdir%%filename%
Popd && rem ..und alten Zustand von Lw/Verz wiederherstellen... ist eine Stilfrage
::--- MoveAll2OneDir.bat
scheitert daran, daß der copy-Befehl irgendwie nicht richtig ist:
Datei nicht gefunden
S:\test>copy s:\test\ s:\target\ 1>nul
Das System kann die angegebene Datei nicht finden.
Irgendwie schaut %%a aber doch gefüllt zu werden, irgendwo im Output steckt ein
S:\test>(if exist s:\emese_target\install.txt ( ...
Nun bin ich in Batch-Proggen absoluter Neuling, mir geht es eigentlich nur um mein Kopier-Problem. Vor allem die Variablen-Deklarierung versteh ich gar nicht. Vielleicht erbarmt sich jemand und richtet mal mein Skript. Und vielleicht bekommt er die Nummerierung auch an den Dateinamen, und nicht an den File-Typ.
Danke
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 33259
Url: https://administrator.de/forum/dateien-kopieren-rekursiv-in-einen-ordner-dubletten-durchnummerieren-33259.html
Ausgedruckt am: 19.02.2025 um 21:02 Uhr
4 Kommentare
Neuester Kommentar
Moin orlet,
da will ich mal ein bisschen ausweichend antworten...
Die beiden Schnipsel, die Du zusammengeschraubt hast, lassen sich zwar zum Fliegen bringen, aber der Batch hat ja gleich drei Designfehler.
1) Weder Datei- noch Verzeichnisnamen mit Leerzeichen ( "C:\Dokumente und Einstellungen"..) werden verarbeitet.
War damals nicht gefordert, aber für einen allgemein verwendbaren Batch muss das rein.
2) Der ist, wie mir Dein Kommentar gezeigt hat, nicht pfleg- und wartbar. Und bei Bätchen ist es immer irgendwann so, dass die angepasst/erweitert/ergänzt werden müssen. Da helfen dann dünn kommentierte Zeilen mit einem halben Dutzend %%a's und %%o's wenig.
3) Die Behandlung der Dateinamens-Kollisionen sollte nicht so fest verdrahtet werden. Ob der Worst-Case nun auf 4 oder auf 8 oder auf 20 gesetzt wird... es wird immer zu kurz greifen. Also sollte das Umbenennen IMMER funktionieren, auch wenn Du 500 Verzeichnisse mit Shareware in einen Ordner kopierst und dort Hunderte Dateien "ReadMe.txt" oder "File.diz" dabei sind.
Ich habe mal eine Skizze gemacht für das Durchwackeln der Quell-Unterverzeichnisse. Ist nur Demo (Kopiert nicht, sondern bringt Bildschirmmeldungen, was er gerade tun WÜRDE).
Das Dateinamen-Kollisionsproblem/die Umbenennerei machen wir später.
Mimik: Das Quellverzeichnis wird von der Wurzel an Unterverteichnis für Unterverzeichnis einzeln "betreten" mit "PushD". Und hinterher wieder mit PopD auf das vorher gültige Verzeichnis zurückgegangen. Dadurch braucht nicht mehr beim Kopieren der ganze Quellpfad angegeben werden.
Mit der Skizze kannst Du erstmal loslaufen... die zeigt vor allem die Auflösung der %~d/ %~p/ %~n /%~x-Variablen.
Mit diesem Wissen kannst Du jede Datei, die irgendwo durch eine For..In..Do-Anweisung durchgeschleift wird, in ihre Pfad/Namens/Extension-Bestandteile aufspalten.
Im Moment ist in dem obigen Schnipsel folgende Demo-Sequenz in der inneren FOR-Schleife:
Und diese Zeile erläutere ich:
For /L %%i in (%MaxDups%,-1,1) do if not exist "%target%\%~n1-%%i%%~x1" set "newname=%target%\%~n1-%%i%%~x1"
For /L %%i in (%MaxDups%,-1,1) do ----------> Von MaxDups an in Einserschritten runterzählen ....44, 43, 42...etc steht in der Variablen %%i
... if not exist "%target%\%~n1-%%i%%~x1"
..wenn nicht folgende Datei existiert...
%target%\ = s:\emese\
%~n1 ......= vom 1.Parameter (dateiname) nur den Namen OHNE Extension beachten == "ReadMe" bei "ReadMe.txt"
-%%i .........= wird zu "-44", "-43", "-42" etc
%%~x1 ........= vom 1.Parameter (dateiname) nur die Extension z.B ".txt"
wenn diese Datei S:\emese\readme-44.txt nicht existiert (der Name FREI ist)
...dann merken wir uns den.
set "newname=%target%\%~n1-%%i%%~xi"
Soweit die Skizze... ich denke, die Anpassungen bekommst Du jetzt hin.
Gruß
Biber
da will ich mal ein bisschen ausweichend antworten...
Die beiden Schnipsel, die Du zusammengeschraubt hast, lassen sich zwar zum Fliegen bringen, aber der Batch hat ja gleich drei Designfehler.
1) Weder Datei- noch Verzeichnisnamen mit Leerzeichen ( "C:\Dokumente und Einstellungen"..) werden verarbeitet.
War damals nicht gefordert, aber für einen allgemein verwendbaren Batch muss das rein.
2) Der ist, wie mir Dein Kommentar gezeigt hat, nicht pfleg- und wartbar. Und bei Bätchen ist es immer irgendwann so, dass die angepasst/erweitert/ergänzt werden müssen. Da helfen dann dünn kommentierte Zeilen mit einem halben Dutzend %%a's und %%o's wenig.
3) Die Behandlung der Dateinamens-Kollisionen sollte nicht so fest verdrahtet werden. Ob der Worst-Case nun auf 4 oder auf 8 oder auf 20 gesetzt wird... es wird immer zu kurz greifen. Also sollte das Umbenennen IMMER funktionieren, auch wenn Du 500 Verzeichnisse mit Shareware in einen Ordner kopierst und dort Hunderte Dateien "ReadMe.txt" oder "File.diz" dabei sind.
Ich habe mal eine Skizze gemacht für das Durchwackeln der Quell-Unterverzeichnisse. Ist nur Demo (Kopiert nicht, sondern bringt Bildschirmmeldungen, was er gerade tun WÜRDE).
Das Dateinamen-Kollisionsproblem/die Umbenennerei machen wir später.
Mimik: Das Quellverzeichnis wird von der Wurzel an Unterverteichnis für Unterverzeichnis einzeln "betreten" mit "PushD". Und hinterher wieder mit PopD auf das vorher gültige Verzeichnis zurückgegangen. Dadurch braucht nicht mehr beim Kopieren der ganze Quellpfad angegeben werden.
:: --- MoveAll2OneDir.bat (ungetestete Skizze)
@echo off & setlocal
goto SkipProsa
Vorüberlegung:
Der alleralleraller-Worst-Case wäre ja theoretisch, wenn alle zu kopierenden
Dateien in den %source%-Unterverzeichnissen gleich hießen (z.B. test.txt).
Dann könnte nur die erste von 100 gefundenen mit ihrem jetzigen Namen geMOVEd/kopiert
werden; alle folgenden müssten umbenannt ("mit LfdNr hochgezählt") werden.
Also--> schaun wir doch, wieviel Dateien/Dubletten wir maximal haben.
Der DIR-Befehl gibt doch am Ende eine Summenzeile aus.
Die Summenzeile fange ich ab und hole mir daraus die Anzahl der Dateien
ohne die Unterverzeichnisse selbst mitzuzählen.
Mimik siehe beim Setzen von %MaxDups% weiter unten.
Dann können die Worst-Case-Konstrukte auch in einer For /L-Konstruktuktion
abgefackelt werden.
:SkipProsa
::BiberTest-Section; Variable BiberTest ist bei mir außerhalb des Batches gesetzt
if defined BiberTest (
Set source=D:\temp\pwroff30
Set target=D:\Temp\Move2OneDir
) ELSE (
Set source=s:\emese
Set target=s:\target
)
:: MaxDups /maximale Duplikate ermitteln == Anzahl aller Dateien überhaupt
for /f %%i in ('Dir /a:-d /s "%source%"^|find "Datei(en)"') do Set "maxDups=%%i"
Pushd "%source%" && Rem In das Source-Verzeichnis wechseln
echo versuche erste for
REM --- Eine Alternative zu: FOR /F %%i IN ('dir /A:D /b /s') DO (
REM --- wäre dies: for /r %source% %%i in (.) do (
REM -- Die vorige Zeile einfach mal so am Prompt testen:
REM --- for /r D:\temp\backup1\ %i in (.) do @echo %~dpnxi
REM Die äußere For-Schleife...Für alle Unterverzeichnisse unterhalb %source%...
FOR /F "delims=" %%i IN ('dir /A:D /b /s') DO (
echo Erstes FOR: Directory [%%i]
REM Zweite For-Schleife...Für alle Dateien im jeweiligen Unterverzeichnis
PushD "%%i"
FOR /F "delims=" %%a in ('dir /b /A:-d ^2^>nul') do (
REM Das "^2^>nul" unterdrückt die Meldung "Datei nicht gefunden",
REM ...Wenn mal ein leeres Unterverzeichnis dabei sein sollte.
REM ---------------------------------------------------------
REM nächste Datei anzeigen mit vollem Pfad und Namen
echo ......[drive-path-name-ext] [%%~dpnxa]
ECHO ......IF not exist "%target%\%%~nxa" ^(
ECHO .........COPY/MOVE "%%~nxa" "%target%\%%~nxa"
ECHO ......^)
)
PopD
)
PopD
goto :eof
Mit der Skizze kannst Du erstmal loslaufen... die zeigt vor allem die Auflösung der %~d/ %~p/ %~n /%~x-Variablen.
Mit diesem Wissen kannst Du jede Datei, die irgendwo durch eine For..In..Do-Anweisung durchgeschleift wird, in ihre Pfad/Namens/Extension-Bestandteile aufspalten.
Im Moment ist in dem obigen Schnipsel folgende Demo-Sequenz in der inneren FOR-Schleife:
...
ECHO ......IF not exist "%target%\%%~nxa" ^(
ECHO .........COPY/MOVE "%%~nxa" "%target%\%%~nxa"
ECHO ......^)
...
- Anmerkung: die Carets ^ vor den Klammern sind nur zur Maskierung für den Echo-Befehl da. Einfach ignorieren.
...
IF not exist "%target%\%%~nxa" (
COPY/MOVE "%%~nxa" "%target%\%%~nxa" >nul
) ELSE (
Call :CopyWithRename "%%~nxa"
)
....
PopD
goto :eof
~~~~~ nach der bisherigen letzten Zeile kann dann noch die Renamerei abgefackelt werden ~~~~
:CopyWithRename Parameter 1 = Dateiname (Name +Extension, z.B ReadMe.txt)
For /L %%i in (%MaxDups%,-1,1) do if not exist "%target%\%~n1-%%i%%~x1" set "newname=%target%\%~n1-%%i%%~x1"
Copy "%1" "%Newname%"
goto :eof
Und diese Zeile erläutere ich:
For /L %%i in (%MaxDups%,-1,1) do if not exist "%target%\%~n1-%%i%%~x1" set "newname=%target%\%~n1-%%i%%~x1"
For /L %%i in (%MaxDups%,-1,1) do ----------> Von MaxDups an in Einserschritten runterzählen ....44, 43, 42...etc steht in der Variablen %%i
... if not exist "%target%\%~n1-%%i%%~x1"
..wenn nicht folgende Datei existiert...
%target%\ = s:\emese\
%~n1 ......= vom 1.Parameter (dateiname) nur den Namen OHNE Extension beachten == "ReadMe" bei "ReadMe.txt"
-%%i .........= wird zu "-44", "-43", "-42" etc
%%~x1 ........= vom 1.Parameter (dateiname) nur die Extension z.B ".txt"
wenn diese Datei S:\emese\readme-44.txt nicht existiert (der Name FREI ist)
...dann merken wir uns den.
set "newname=%target%\%~n1-%%i%%~xi"
Soweit die Skizze... ich denke, die Anpassungen bekommst Du jetzt hin.
Gruß
Biber
Mit Anpassungen meinte ich, ob Du Du nun ein COPY und danach DEL machst oder ein MOVE oder irgendwas in eine LogDatei schreibst etc...
Aber ich denke, die eigentliche Frage ist beantwortet - ich setze den beitrag mal auf "Gelöst".
Grüße
Biber