enting1991
Goto Top

Per Batch zwei Verzeichnisse zusammenlegen - ohne copy, xcopy oder robocopy

Hallo, liebe Gemeinde,

ich stehe vor einem Problem, welches ich selbst nicht problemlos lösen kann und hoffe auf eure Hilfe.
Als bisher stiller Mitleser habe ich hier schon oft Antworten auf meine Fragen gefunden und hoffe daher nun auf eure kompetente Unterstützung.

Ich danke jedem, der sich meinem Problem annimmt, schon im Voraus!

Folgendes Problem:
Ich möchte per Batch mindestens zwei Verzeichnisse mit z.T. identischem Inhalt zusammenlegen, sodass nur noch ein Verzeichnis übrig bleibt. Dabei soll auf copy, xcopy, robocopy usw. verzichtet werden - ich möchte nicht, dass die Dateien kopiert und anschließend aus dem "Quellverzeichnis" gelöscht werden, sondern einen wirklich move-Vorgang, bei dem Dateien verschoben bzw. die Verzeichnisse einfach umbenannt werden. Ein Kopiervorgäng wäre bei den anfallenden Datenmengen sehr zeitraubend.

Dazu ein paar Details bzw. Annahmen anhand eines Beispiels.
Verzeichnis 1 heißt "source" und stellt das Quellverzeichnis dar.
Verzeichnis 2 heißt "target" und stellt das Zielverzeichnis dar.
Beide, sowohl "source" als auch "target" haben viele Unterordner und darin -Dateien.
Der gesamte Inhalt von "source" soll nun in "target" verschoben werden. Dabei sollen alle Daten, die sowohl in "source" als auch in "target" existieren, in "target" überschrieben werden.
Am Ende soll das Verzeichnis "target" alle Daten aus beiden Verzeichnissen enthalten, während "source" leer ist.

Zu diesem Zweck habe ich bereits einige Dinge probiert.

Versuch 1: Mit dem Befehl
move /Y "source" "target"  
wird natürlich einfach der komplette Ordner "source" in den Ordner "target" verschoben. Das ist aber nicht der Sinn der Sache.
Mögliche Variationen funktionieren nicht, da in keinem Fall die Unterverzeichnisse (und somit die komplette Verzeichnisstruktur) mit verschoben werden. Außerdem verweigert der Befehl den Dienst wenn es den Zielpfad bereits gibt mit der Meldung "Zugriff verweigert".

Versuch 2: Die Nutzung des Befehls
replace /A "source\*.*" "target"  
bzw.
replace /R "source\*.*" "target"  
bricht entweder mit Fehlermeldungen wie "Keine Dateien gefunden" ab oder läuft durch, kopiert/verschiebt aber nichts. Verschiedene Variationen mit anderen Parametern halfen nicht.


Zuletzt schossen mir noch Möglichkeiten durch den Kopf, wie ich per FOR-Schleife und einem Befehl wie
for /F "delims=" %%i in ('dir /B /S /A:D "source"') do (  
   move /Y "%%~i\*.*" "target\"  
)
o.ä. eine komplette Liste aller Verzeichnisse und Unterverzeichnisse bekommen können müsste, durch die ich wiederum die Dateien in den Verzeichnissen per "move /Y" verschieben und in "target" überschreiben können müsste. Problem dabei ist, dass es sich ggf. um bis zu 20GB Daten handelt, die aus vielen kleinen Dateien in vielen Unterordnern usw. bestehen. Sollte die Methode Erfolg haben, wäre das trotzdem sehr performancelastig, umständlich und würde ggf. lange dauern.


Fazit:
Gibt es keine Möglichkeit, per Batch quasi ein "Ausschneiden" und "Einfügen" aller Verzeichnisse und Unterordner wie im Explorer vorzunehmen? Ich möchte dabei, wenn möglich, auf Windows-eigene Mittel zurückgreifen und, wie gesagt, keinen Kopiervorgang (der bei >20GB Daten lange dauert), sondern einen Verschiebevorgang erzielen.

Ich wäre dankbar für jede Hilfe und teste inzwischen, ob ich Erfolg habe, wenn ich weiter teste...

Content-ID: 187633

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

Ausgedruckt am: 23.11.2024 um 23:11 Uhr

Biber
Biber 08.07.2012 um 15:47:10 Uhr
Goto Top
Moin enting1991,

willkommen im Forum.

Rückfrage. Wenn gelten soll:
Der gesamte Inhalt von "source" soll nun in "target" verschoben werden. Dabei sollen alle
Daten, die sowohl in "source" als auch in "target" existieren, in "target" überschrieben werden.
Am Ende soll das Verzeichnis "target" alle Daten aus beiden Verzeichnissen enthalten, während "source" leer ist.

... dann muss auch gelten, dass KEINE einzige Datei existiert, die nur in "source", aber nicht in "target" existiert. Dem ist so?

Wenn ja, dann sollte doch dein Versuch 2 mit "Replace" zum Ziel führen.
>replace /?
Ersetzt Dateien.

REPLACE [Laufwerk1:][Pfad1]Dateiname [Laufwerk2:][Pfad2] [/A] [/P] [/R] [/W]
REPLACE [Laufwerk1:][Pfad1]Dateiname [Laufwerk2:][Pfad2] [/P] [/R] [/S] [/W][/U]

  [Laufwerk1:][Pfad1]Dateiname  Die Quelldatei(en)
  [Laufwerk2:][Pfad2]           Das Verzeichnis, in dem Dateien ersetzt
                                werden sollen.
  /A        Fügt neue Dateien dem Zielverzeichnis hinzu. Kann nicht mit den
            Optionen /S oder /U verwendet werden.
  /P        Fordert vor dem Ersetzen oder Hinzufügen einer Datei zur
            Bestätigung auf.
  /R        Ersetzt sowohl schreibgeschützte als auch ungeschützte Dateien.
  /S        Ersetzt auch Dateien in Unterverzeichnissen des
            Zielverzeichnisses. Kann nicht zusammen mit der Option /A
            verwendet werden.
  /W        Wartet am Beginn auf das Einlegen einer Diskette.
  /U        Ersetzt (aktualisiert) nur Dateien, die älter als die Quelldateien
            sind. Kann nicht zusammen mit der Option /A verwendet werden.

Allerdings mit den Parametern /S und /U [und ggf. /P beim Testen].

Grüße
Biber
enting1991
enting1991 08.07.2012 um 16:03:11 Uhr
Goto Top
Zitat von @Biber:
... dann muss auch gelten, dass KEINE einzige Datei existiert, die nur in "source", aber nicht in "target"
existiert. Dem ist so?

Nein, dem ist leider nicht so - und ich denke, da liegt der Hund begraben.

Außerdem fiel mir zu meiner Idee von weiter unten noch auf, dass ich es zwar per "%%~nxi" schaffe, nur die Namen der Unterverzeichnisse als Variable zu nutzen, um die gleiche Ordnerstruktur in "target" zu erzielen wie in "source" (statt dem vollqualifizierten Pfad inkl. Laufwerksbuchstabe usw., den der DIR-Befehl nun mal ausspuckt), allerdings wird dann immer nur das unterste Verzeichnis genommen.

Gäbe es in diese Richtung vielleicht eine Möglichkeit?

for /F "tokens=* delims=" %%i in ('dir /S /B /A:D "source"') do (  
	move /Y "%%~i\*.*" "target\%%~nxi\"  
)
scheint mir nah an einer Lösung dran zu sein, nur fehlt unter "target" dann die Verzeichnisstruktur.
Biber
Biber 08.07.2012 um 16:32:02 Uhr
Goto Top
Moin enting1991,

ja nee... natürlich lässt sich auch eine FOR-Anweisung (allerdings für diesen Zweck eine FOR /R oder FOR /D-Anweisung) zum Fliegen bringen, aber...

... bitte erst das Konzept zu Ende denken, dann das handwerkliche Zusammenklöppeln weitertreiben.

Wenn bisher im "source"-Verzeichnis ein paar Dateien rumliegen, die nicht im Target vorhanden sind, dann würde ich aus meinen Erfahrungen heraus doch erst einmal diese "Auffälligkeit" näher betrachten wollen.
Sprich - sind das denn wirklich Dateien, die nach "target" gehören?
Oder sind das manuell erzeugte Kopien mit der Namensendung "_test" oder "_2012-07-03"?

Ich weiss ja nicht genau, was sich inhaltlich hinter den "source" und "target"-Inhalten verbirgt.
Wenn es vergleichbar ist mit irgendwelchen "entwicklung"/"test"/"QS"/"Prod"-Verzeichnisstrukturen, die ich so kenne, dann
a) ist es normal, dass ich in "entwicklung" und "test" mehr Dateien habe als in "Prod"
b) und nein, ich will nicht alles aus "test" unbesehen nach "prod" übernehmen.

Wenn du nun einfach ein "Replace /S /u" auf das "target"-Verzeichnis machst, wieviel bleibt denn über?
Oder andersrum, wenn du nur alles in "target" mit dem jetzigen Stand aus "source" blind überklatschen kannst - wieso hättest du jemals damit anfangen sollen, das Ganze in "source" und "target" zu trennen?

Die Sinnhaftigkeit der Anforderung leuchtet mir noch nicht ganz ein.

Grüße
Biber
enting1991
enting1991 08.07.2012 um 17:02:26 Uhr
Goto Top
Ich versuche mal, das genauer zu erläutern.

Gehen wir davon aus, dass in "target" Dateien sind, die bereits verarbeitet wurden. Diese sollen niemals gelöscht werden, sondern bestehende durch ggf. neuere Dateien überschrieben. Ebenfalls sollen neu hinzukommende Dateien eingefügt werden.
Demgegenüber sind in "source" Dateien, die noch verarbeitet werden sollen. NACH der Verarbeitung müssen diese also zu "target".

In "target" sind HEUTE die Dateien A, B, M, N, Y, Z. In "source" sind HEUTE die Dateien A, M, Y - die sollen in "target" überschrieben werden.
In "target" sind MORGEN die Dateien A, B, M, N, Y, Z. In "source" sind MORGEN die Dateien A, G, H, O, Y, Z - die sollen in "target" verschoben respektive überschrieben werden.

Aus Performancegründen soll nicht kopiert und anschließend gelöscht, sondern verschoben werden.
Die Daten in "source" und "target" sind also von Tag zu Tag auf's Neue komplett anders gegeben. Mal würde es ein "replace" vielleicht tun, aber leider nicht immer. Und der "move"-Befehl arbeitet ja leider nicht mit Unterverzeichnissen, weshalb mir eine FOR-Schleife fast unumgänglich scheint. Doch wie müsste die aussehen?

Ich hoffe, ich habe mich verständlich ausgedrückt.
pieh-ejdsch
pieh-ejdsch 08.07.2012 aktualisiert um 18:16:56 Uhr
Goto Top
moin enting,

ich hab da mal schnell was zusammengekloppt.
Hauptsächlich nutze ich die Parameter aus XCOPY:
Eine Hilfe ist Integriert.
@echo off
setlocal
if "%~1" equ "/?" goto :Help  
if not exist "%~1" goto :Help  
if not exist "%~2" goto :Help  

set Quelle=%1
set Ziel=%2
set "List="  
set "xcopyParam="  
for %%i in (%3 %4 %5 ) do (if /i "%%~i" equ "/L" set "List=echo"  
  if /i "%%~i" equ "/U" call set "xcopyParam=%%xcopyParam%%%%~i "  
  if /i "%%~i" equ "/D" call set "xcopyParam=%%xcopyParam%%%%~i "  
)

 rem Verzeichnisse erstellen
if not defined List xcopy %xcopyParam% /TE "%~1\*" "%~2"  

 rem Liste abarbeiten
for /f delims^= %%i in ('echo xva^|xcopy %xcopyParam% /LFSE "%~1\*" "%~2\" ^|Find /v "Datei(en) kopiert"') do (  
  set File=%%i
  call :Move
)
if not defined List rd /s "%~1"  
exit /b 0

:Move
set "File=%File: -> =*%"  
for /f "tokens=1,2 delims=*" %%i in ("%File%") do if "%%j" neq "" %List% move "%%~i" "%%~j"  
exit /b


:help
echo Verschiebt den Inhalt der Quelle ins Ziel.
echo Loescht die Quelle auf Nachfrage.
echo(
echo Syntax: %~n0 Quelle Ziel [/L] [/U] [/D]
echo(
echo  /L	Zeigt nur das Ergebniss an.
echo  /U	Verschiebt nur Dateien, die im Zielverzeichnis vorhanden sind.
echo  /D	Verschiebt nur Dateien, welche neuer als die im Ziel sind.

[Edit]
in der Variable %File% ? mit * ausgetauscht
[/Edit]

Gruß Phil
enting1991
enting1991 08.07.2012 aktualisiert um 21:06:27 Uhr
Goto Top
Phil, du bist ein Genie!

Wie es aussieht, klappt das nun wunderbar.
Ich danke dir wirklich sehr, du hast mir den Tag gerettet ;)

Beste Grüße und bis demnächst,
David


Nachtrag:

Ich habe nun das Skript für meine Zwecke (als fest integrierter Bestandteil in einem bereits bestehenden Skript) angepasst und gekürzt. Die Lösung wollte ich hier noch kundtun, falls mal jemand so etwas benötigen sollte.
An dieser Stelle erneut mein Dank an alle Helfer und meine Hochachtung vor der genialen Lösung. Ich konnte mal wieder was dazulernen und weiß schon, dass ich das in Zukunft oft gut gebrauchen werden könne ;)

REM Die folgende Schleife erstellt nur den Verzeichnisbaum vom %QUELLPFAD% im %ZIELPFAD%.
for /F "tokens=* delims=" %%i in ('echo n^|xcopy /TED "%QUELLPFAD%" "%ZIELPFAD%"') do REM Platzhalter  

REM Die folgende Schleife generiert eine Liste der Dateien, die neuer sind als die bestehenden.
REM Diese Liste wird als "Quelldatei -> Zieldatei" in die Varible "file" gespeichert.  
REM Der "->" wird dann ersetzt durch einen "*", damit die Schleife am Ende anhand des Delimiters "*"  
REM die Varible "file" teilt in Quelldatei und Zieldatei und die Dateien verschiebt.  
REM Es werden ALLE Dateien verschoben bis auf die, die im %QUELLPFAD% nicht neuer sind als im %ZIELPFAD%.
for /F "tokens=* delims=" %%i in ('xcopy /LFEDY "%QUELLPFAD%" "%ZIELPFAD%" ^|find "->"') do (  
	set file=%%i
	set "file=!file: -> =*!"  
	for /F "tokens=1,2 delims=*" %%j in ("!file!") do move /Y "%%~j" "%%~k" >nul 2>&1  
)

REM Am Ende wird der %QUELLPFAD% gelöscht. Die Anweisung "rmdir" steht 2x, um das Löschen zu erzwingen.  
rmdir /S /Q "%QUELLPFAD%" >nul 2>&1  
rmdir /S /Q "%QUELLPFAD%" >nul 2>&1  
So klappt es bei mir wunderbar.
bastla
bastla 09.07.2012 um 01:12:26 Uhr
Goto Top
Hallo enting1991 und willkommen im Forum!

Danke für das Posten Deiner angepassten Lösung. face-smile

Der Vollständigkeit halber anzumerken wäre noch, dass einerseits
setlocal enabledelayedexpansion
vorweg benötigt wird und dass andererseits deswegen Dateien/Pfade mit enthaltenen "!" nicht verschoben werden.
Zeile 2 sollte sich auf
xcopy /TE "%QUELLPFAD%" "%ZIELPFAD%"
verkürzen lassen.
PH hatte "move" ohne "/y" verwendet - Letzteres wird auch in Deinem Ansatz nicht benötigt, da durch "move" in einem Batch ohnehin defaultmäßig überschrieben wird ...

Grüße
bastla

P.S.: Wozu soll das zweite "rmdir" ("rd" täte es ganz nebenbei auch) gut sein (erzwungen wird das Löschen doch schon durch "/s/q")?
enting1991
enting1991 09.07.2012 um 06:28:06 Uhr
Goto Top
Zu 1:
Ja vollkommen richtig.

Zu 2:
Wenn ich Zeile 2 auf so verkürze, werde ich komischerweise gefragt, ob ich bereits vorhandene Dateien überschreiben will. Das trifft
Allerdings nur auf Dateien zu, die sich in der erster Unterebene (also bspw. "%QUELLFAD%\abc\xyz.txt") befinden. Warum das
So ist, weiß ich nicht. Mit meiner Zeile wird dann ein "n" als Antwort übergeben, was es ja auch tut.

Zu 3:
Das "move /Y" geht auch ohne,
Stimmt. Danke.

Zu 4:
Wenn ich nur einmal "rmdur /S /Q" nehme, bekomme ich ggf. die Meldung "Verzeichnis ist nicht leer." und dann ist alles bis auf das Vereich kis selbst gelöscbt.

Danke für deine Anmerkungen!
bastla
bastla 09.07.2012 aktualisiert um 10:25:29 Uhr
Goto Top
Hallo enting1991!

Zu 2:
Warum das So ist, weiß ich nicht.
Hatte ich so nicht getestet und kann ich leider auch nicht erklären face-sad - Alternative:
xcopy /TEIY "%QUELLPFAD%" "%ZIELPFAD%"
- es wird ja beim Erstellen einer Verzeichnisstruktur nur wirklich eine Datei überschrieben, wenn sie den gleichen Namen wie ein zu erstellendes Verzeichnis trägt - und dann hast Du in jedem Fall ein Problem ...

Zu 4: Kann ich zwar nicht nachvollziehen, aber wenn es für Dich so funktioniert ...

Grüße
bastla
pieh-ejdsch
pieh-ejdsch 09.07.2012 aktualisiert um 15:57:28 Uhr
Goto Top
moin Zammnander,

Hatte ich so nicht getestet und kann ich leider auch nicht erklären
aber ich:
Wenn xcopy mit der Option /Liste mal nur auf sowie ohne Option /Yes alles überschreiben gestartet wird,
dann wird trotzt der "Nur Auflistung" immer eine Nachfrage beim Überschreiben der Dateien erfolgen (natürlich nur simuliert)
D:\Letzte\Neues Textdokument.txt überschreiben (Ja/Nein/Alle)?
Und zusätzlich, wenn das Ziel nicht existiert - bei Option /Is'n Verzeichnis das Ziel ... bzw. Zielangabe ohne Backslash:
Ist das Ziel D:\abc ein Dateiname
oder ein Verzeichnisname
(D = Datei, V = Verzeichnis)?
werde ich komischerweise gefragt, ob ich bereits vorhandene Dateien überschreiben will. ...
Genau (auch wenn es so aussieht, ist es hier nur Fast eine Simulation).
Und wenn du das erste Nein als erste Anwort verbraten hast, dann wirst Du je weitere zu überschreibende Datei auch drei Nachfragen haben.

Wenn Du dreimal eine Andere Anwortmöglichkeit gibst (ist bei Deiner echo Verkettung ja keine Antwort mehr da, aber es kommt als Simulierte Eingabetaste an), wird bei der Datei Abgerochen und mit der Nächsten Datei weitergemacht.

Wüderst Du zB. nur die erste und die dritte bis zur siebten Datei von einem Verzeichnis in ein anderes (vielleicht auch neues) Verzeichnis kopieren/überschreiben wollen, könntest Du es sehr vereinfacht auch so schreiben:
echo VjNjJjJj |xcopy /Py D:\Verzeichnis1\*.* D:\Verzeichnis2

Da bei Dir die Nachfrage zum Überschreiben wegen nur Ordnererstellen ist ist es eh Irrelevant, da ein Ordner schon vorher bestehen muss, wenn dort eine Datei überschieben werden würde.

Nur bei der Vollständigen Simulation gebe ich gerne die Verkettung echo xVA| dem xcopy mit, damit auf jeden Fall ein Verzeichnis erstellt wird und Alle Dateien mitgenommen werden.
Das x gebe ich ja nur mit um etwas Verwirrung zu stiften.

Theoretisch müsste zweimal A stehen, falls auch die Option /Pestätige jede Datei verwendet wird.
Da wird mir aber der xcopy /Log nicht richtig geschrieben.
Daher ist bastlas Alternative im Grunde die erste Wahl.

Gruß Phil
bastla
bastla 09.07.2012 um 15:59:28 Uhr
Goto Top
@ph
Es ging ja nicht um "/L", sondern um
xcopy /TE "%QUELLPFAD%" "%ZIELPFAD%"
und die dort auftauchende Frage nach dem Überschreiben von Dateien, die in einer/der ersten Unterordnerebene liegen ...

Grüße
bastla
pieh-ejdsch
pieh-ejdsch 09.07.2012 um 16:08:53 Uhr
Goto Top
moin bastla,

bei der Simulation /LE kommen diese Frage auch genau wie bei /TE .
Das liegt daber nicht an der Unterordnerebene (vllt sah es nur so aus), sondern daran wie ich es oben mit der (Verkettung)Simulation der Eingabe von nichts beschrieben habe.

Redmont wollte halt eine Echte Simulation.

Gruß Phil