obi134
Goto Top

Dateien aus Unterverzeichnissen in einen Ordner verschieben - mit Batch?

Hi ihr Batch- Bastler unter euch face-wink
Ich habe leider überhaupt keine Ahnung von Batch- Dateien und bitte somit um eure fachkundige Hilfe!

Ich bin auf der Suche nach einer Batch, die Dateien aus einem Verzeichnis "flach" in einen Ordner packt. Also aus einem Verzeichnis mit mehreren Unterverzeichnissen in einen zentralen Ordner. Ich habe schon

Dateien verschieben und umbenennen mit Batch

gefunden, kann damit aber nicht so viel anfangen. Außerdem habe ich auch

c't - Dateien aus Unterverzeichnissen zusammenführen

gefunden, was die Dateien wohl kopiert, aber nicht verschiebt (Ich hoffe die Links sind sowas wie die gemeinten erlaubten Zusatzverlinkungen, ansonsten ist das nicht böse gemeint).
Bei mir ist das Problem, dass die vielen Bilder teilweise auch gleich heißen und ich nicht ganz nachvollziehen kann, welche er von den über 1000 Dateien kopiert hat und welche ich mit "n" vor dem überschreiben geschützt habe.
Meinetwegen können in dem Zielverzeichnis auch alle "bild1.jpg", "bild2.jpg" usw. heißen.
Die Lösung von Heise, dass man in die Batch in der Eingabeaufforderung mit den entsprechenden Parametern aufrufen kann, finde ich sehr gut und universell. Vielleicht wäre soetwas auch möglich? Eventuell auch noch mit dem Zusatz, wie der Präfix der entsprechenden Zieldateien sein soll z.B. "bild" oder "foto"?

Ich hoffe ich habe mich verständlich ausgedrückt. Ansonsten bitte rückfragen.
Könntet Ihr mir bitte helfen?

Gruß
Tobias

Content-ID: 127222

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

Ausgedruckt am: 22.11.2024 um 05:11 Uhr

bastla
bastla 15.10.2009 um 19:28:37 Uhr
Goto Top
Hallo obi134 und willkommen im Forum!

Wenn's tatsächlich nur darum geht, alle Bilder (eines bestimmten Dateityps) mit fortlaufender Nummerierung in einem Ordner zu sammeln, könnte das Gerüst etwa so aussehen:
@echo off & setlocal
set "Sammel=D:\Sammelordner"  
set "Quelle=D:\Quellordner"  
set "Prae=bild"  
set "Typ=jpg"  

set /a Nr=1000001

for /r "%Quelle%" %%i in (*.%Typ%) do call :ProcessFile "%%i"  
goto :eof

:ProcessFile
move %1 "%Sammel%\%Prae%%Nr:~-5%.%Typ%"  
set /a Nr+=1
goto :eof
Wenn Du eine Parameterübergabe dem Anpassen der Zeilen 2 bis 5 vorziehst, kannst Du diese Zeilen etwa so schreiben:
set "Sammel=%~1"  
set "Quelle=%~2"  
...
Allerdings solltst Du dann eine Prüfung der Parameter auf Vollzähligkeit ergänzen (als Vorlage dafür kann zB das verlinkte c't-Script dienen). Auch Existenz von Quell- und Zielordner wären zu prüfen (bzw letzterer ggf zu erstellen).

Der Inhalt des Zielordners wird ebenfalls vorweg nicht geprüft, sodass also Dateien mit dem selben Präfix (kommentarlos) überschrieben würden ...

Falls die führenden Nullen der laufenden Nummer nicht gewünscht wären, müsstest Du
move %1 "%Sammel%\%Prae%%Nr:~-5%.%Typ%"
durch
move %1 "%Sammel%\%Prae%%Nr%.%Typ%"
ersetzen. (Die Schreibweise mit .%Typ% anstelle von %~x1 hat übrigens den Sinn, eine einheitliche Schreibweise - hinsichtlich Groß-/Kleinschreibung - zu errreichen.)

Grüße
bastla

P.S.:
... welche ich mit "n" vor dem überschreiben geschützt habe.
habe ich nicht verstanden und daher auch nicht berücksichtigt.
obi134
obi134 15.10.2009 um 20:04:53 Uhr
Goto Top
Hi bastla!
Danke für deine superschnelle Antwort!
Ich werde mich morgen, ansonsten nächstes Wochenende mal daran setzen, das Skript zu testen und anzupassen.
Ich werde dann mal das mit der Übergabe ausprobieren und dann die Überprüfung der Parameter, sowie die Prüfung des Zielordners hinzufügen, wenn ich das hinbekomme face-wink

mit "n" meinte ich folgendes:
Bei dem Kopieren war eine Datei schon vorhanden. Ich hatte die Option /y weggelassen, um gefragt zu werden (ja/nein/alle) und diese habe ich alle mit n beantwortet, um keine Datei zu überschreiben.
Schönen Abend noch!

Gruß
Tobias

Edit:
Außerdem probiere ich noch das mit den Leerzeichen im Dateinamen zu managen face-wink
bastla
bastla 15.10.2009 um 20:47:55 Uhr
Goto Top
Hallo obi134!

Nur zur Sicherheit: Im Entwurf oben wird verschoben und ggf ohne Rückfrage überschrieben - um das zu vermeiden, müsstest Du dem move ein explizites /-Y hinzufügen!
Außerdem probiere ich noch das mit den Leerzeichen im Dateinamen zu managen face-wink
Leerzeichen (egal, ob bereits vorhandene oder ev hinzuzufügende) sollten in meinem Vorschlag nicht zu Problemen führen, da alle Dateinamen/Pfade unter Anführungszeichen stehen.

Grüße
bastla
obi134
obi134 15.10.2009 um 21:16:20 Uhr
Goto Top
Hi bastla!
Ich habe mich gerade doch noch etwas an das File gesetzt.
Bin so weit gekommen:

@echo off & setlocal

if %2. == . (
  echo Nicht genug Parameter. 
  echo Aufruf:   %~n0 ^<Quelle^> ^<Ziel^> [Maske] Präfix
  echo Beispiel: %~n0 c:\Bilder d:\Backup *.jpg bild
  echo           Kopiert alle *.jpg-Dateien aus c:\Bilder und Unterordnern "flach"  
  echo           nach d:\Backup. Ist [Maske] nicht angegeben, werden alle Dateien
  echo           kopiert. Präfix gibt den Datei- Präfix an.
  exit /b
)

if %4. == . (
  echo Nicht genug Parameter.
  echo Aufruf:   %~n0 ^<Quelle^> ^<Ziel^> [Maske] Präfix
  echo Beispiel: %~n0 c:\Bilder d:\Backup *.jpg bild
  echo           Kopiert alle *.jpg-Dateien aus c:\Bilder und Unterordnern "flach"  
  echo           nach d:\Backup. Ist [Maske] nicht angegeben, werden alle Dateien
  echo           kopiert. Präfix gibt den Datei- Präfix an.
  exit /b
)

set "Quelle=%~1"  
set "Sammel=%~2"  
set "Typ=%3"  
set "Prae=%4"  
set /a Nr=00001

if %Typ%. == . (
  set "Typ=*"  
  echo Es werden alle Dateitypen verschoben!
)

echo Kopiere %Typ% von %Quelle% nach
     %Sammel% ...

for /r "%Quelle%" %%i in (*.%Typ%) do call :ProcessFile "%%i"  
goto :eof

:ProcessFile
move /-Y %1 "%Sammel%\%Prae%%Nr:~-5%.%Typ%"  
set /a Nr+=1
goto :eof

dir /s "%Quelle%\%Typ%" > %~n0.log  

Ich hoffe, dass ich trotz meiner sehr großen Unwissendheit über Batch und Co alles bis jetzt korrekt kopiert und angepasst habe face-wink
Es fehlt dann noch die Abfrage des Zielordners und evtl. eine Abfrage, wie hoch der Zähler bei den bereits vorhandenen Dateien ist (wenn das überhaupt geht face-wink

Schönen Abend noch!
Gruß
Tobias
bastla
bastla 15.10.2009 um 21:33:09 Uhr
Goto Top
Hallo obi134!

Da Du ja zumindest 3 Parameter brauchst, wäre
if %3. == . ( 
zu verwenden, und der optionale Parameter "Maske" als Letzter einzugeben (und zwar ohne "*" und ohne Punkt).
In der Zeile 28 fehlt die "1" am Anfang - richtig wäre:
set /a Nr=100001
Zahlen werden ohne führenden Nullen gespeichert, sodass Du diese Nullen nur erhältst, indem Du eine größere Zahl verwendest und die entsprechende Stellenanzahl (im Beispiel waren es 5) am Ende der Zahl entnimmst (siehe auch unten).
... eine Abfrage, wie hoch der Zähler bei den bereits vorhandenen Dateien ist (wenn das überhaupt geht face-wink
Ließe sich etwa so (als Ersatz der Zeile 28) realisieren:
set "Letzte=00000"  
for /f %%i in ('dir /b /on "%Sammel%\%Prae%*.%Typ%" 2^>nul') do set "Letzte=%%~ni"  
set /a Nr=1%Letzte:~-5%+1
Damit werden die entsprechenden Dateinamen (wegen der fixen Länge der laufenden Nummer auch richtig) sortiert durchlaufen und als Zwischenergebnis in der Variablen %Letzte% für den Namen mit der höchsten Nummer nur der Dateiname (also zB ohne ".jpg") gespeichert - dessen letzte 5 Stellen werden an 1 angefügt, woraus sich zB 100012 ergibt und dieses Ergebnis gleich noch um 1 erhöht, um aus dem Ergebnis (zB 100013) wiederum die letzten 5 Stellen (dann also 00013) als nächste Nummer verwenden zu können.
Abfrage des Zielordners zB so:
if not exist "%Sammel%" md "%Sammel%"
Deine Zeile 46 wird nie erreicht, da der Batch mit Zeile 39 endet - daher zwischen die Zeilen 38 und 39 einfügen - außerdem enthält ja %Typ% weder "*" noch ".", daher: "%Quelle%\*.%Typ%" verwenden ...

Grüße
bastla
obi134
obi134 16.10.2009 um 14:02:33 Uhr
Goto Top
Hey bastla face-wink du hast es voll drauf ^^
Der Code sieht nun so aus:

@echo off & setlocal

if %3. == . (
  echo Nicht genug Parameter.
  echo Aufruf:   %~n0 ^<Quelle^> ^<Ziel^> Präfix [Maske] 
  echo Beispiel: %~n0 c:\Bilder d:\Backup jpg bild
  echo           Kopiert alle *.jpg-Dateien aus c:\Bilder und Unterordnern "flach"  
  echo           nach d:\Backup. Präfix gibt den Datei- Präfix an.Ist [Maske] 
  echo           nicht angegeben, werden alle Dateien kopiert. 
  exit /b
)

set "Quelle=%~1"  
set "Sammel=%~2"  
set "Prae=%3"  
set "Typ=%4"  
set "Letzte=00000"  

if not exist "%Sammel%" md "%Sammel%"  

for /f %%i in ('dir /b /on "%Sammel%\%Prae%*.%Typ%" 2^>nul') do set "Letzte=%%~ni"  
set /a Nr=1%Letzte:~-5%+1

echo Nächste Dateinummer ist %Letzte%

if %Typ%. == . (
  set "Typ=*"  
  echo Es werden alle Dateitypen verschoben!
)

echo Kopiere %Typ% von %Quelle% nach
     %Sammel% ...

for /r "%Quelle%" %%i in (*.%Typ%) do call :ProcessFile "%%i"  
dir /s "%Quelle%\*.%Typ%" > %~n0.log  
goto :eof

:ProcessFile
move /-Y %1 "%Sammel%\%Prae%%Nr:~-5%.%Typ%"  
set /a Nr+=1
goto :eof

Kann man nach Zeile 32 noch eine Bestätigung einbauen, sodass man noch abbrechen kann, falls was nicht passt?
z.B. Fortfahren? (ja/nein)

Gruß
Tobias
bastla
bastla 16.10.2009 um 14:43:07 Uhr
Goto Top
Hallo obi134!

Etwa so:
set "Eingabe="  
set /p Eingabe=Fortfahren? (ja/nein) 
if /i "%Eingabe:~0,1%" neq "j" goto :eof  
Grüße
bastla
obi134
obi134 16.10.2009 um 14:56:13 Uhr
Goto Top
Okay, habe jetzt

@echo off & setlocal

if %3. == . (
  echo Nicht genug Parameter.
  echo Aufruf:   %~n0 ^<Quelle^> ^<Ziel^> Praefix [Maske] 
  echo Beispiel: %~n0 c:\Bilder d:\Backup jpg bild
  echo           Kopiert alle *.jpg-Dateien aus c:\Bilder und Unterordnern "flach"  
  echo           nach d:\Backup. Praefix gibt den Datei- Praefix an.Ist [Maske] 
  echo           nicht angegeben, werden alle Dateien kopiert. 
  exit /b
)

set "Quelle=%~1"  
set "Sammel=%~2"  
set "Prae=%3"  
set "Typ=%4"  
set "Letzte=00000"  

if not exist "%Sammel%" md "%Sammel%"  

for /f %%i in ('dir /b /on "%Sammel%\%Prae%*.%Typ%" 2^>nul') do set "Letzte=%%~ni"  
set /a Nr=1%Letzte:~-5%+1

echo Nächste Dateinummer ist %Letzte%

if %Typ%. == . (
  set "Typ=*"  
  echo Es werden alle Dateitypen verschoben!
)

echo Kopiere %Typ% von %Quelle% nach
     %Sammel% ...

set /p Eingabe=Fortfahren? (ja/nein) 
if /i "%Eingabe:~0,1%" neq "j" goto :eof  

for /r "%Quelle%" %%i in (*.%Typ%) do call :ProcessFile "%%i"  
dir /s "%Quelle%\*.%Typ%" > %~n0.log  
goto :eof

:ProcessFile
move /-Y %1 "%Sammel%\%Prae%%Nr:~-5%.%Typ%"  
set /a Nr+=1
goto :eof

Dann kommt folgendes:

C:\>flatmove "C:\Dokumente und Einstellungen\Obi\Desktop\test" "C:\Dokumente und
Einstellungen\Obi\Desktop\test12" text txt
Nõchste Dateinummer ist 00000
Kopiere txt von C:\Dokumente und Einstellungen\Obi\Desktop\test nach
Der Befehl "C:\Dokumente" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
Fortfahren? (ja/nein) j
Datei nicht gefunden

was ist da noch falsch?
Danke!
Gruß
Tobias
bastla
bastla 16.10.2009 um 15:11:03 Uhr
Goto Top
Hallo obi134!

Entweder die Zeilenschaltung am Ende der Zeile 31 entfernen oder ein "echo" an den Anfang der Zeile 32 setzen ...

Noch ein Hinweis: Zum Testen in Zeile 1 "echo on" anstelle von "echo off" verwenden - so wird jeder Befehl vor der Ausführung angezeigt und Du kannst Fehler leichter erkennen (besonders, wenn Du mit
flatmove "C:\Dokumente und Einstellungen\Obi\Desktop\test" "C:\Dokumente und
Einstellungen\Obi\Desktop\test12" text txt >Ablauf.txt 2>&1
alle Ausgaben (auch jene auf dem Fehlerkanal 2) in eine Datei umleitest (die Eingabe der Bestätigung musst Du allerdings in diesem Fall "blind" machen).
Ansonsten wären noch "Textmängel" anzumerken face-wink: "Nächste" anstelle von "Letzte" Dateinummer (oder eben die Ausgabe von %Nr%) und "Kopiere" anstelle von "Verschiebe" ...

Grüße
bastla
obi134
obi134 23.10.2009 um 11:22:58 Uhr
Goto Top
Da ich im Moment etwas krank bin dauert es noch etwas, bis ich das Skript mal austesten kann...
Ich melde mich dann mal, wenn ich es getestet habe.
Gruß
Tobias
obi134
obi134 01.11.2009 um 13:55:27 Uhr
Goto Top
Klappt wunderbar!
Danke nochmal!
Gruß
Tobias