00snickers
Goto Top

Batch um Dateien aus Unterordnern in den ersten Unterordner zu verschieben

Hallo an alle erst einmal.

Wie sich herrausgestellt hat, habe ich ein etwas komplexeres Problem (zumindest für mich).
In einem Ordner D:\Daten\ befinden sich nach einem automatischen Suchlauf viele verschiedene
Unterordner, deren Namen wie folgt aufgebaut sind: regionaltimes.com aber auch www.dailytimes.com.pk, usw.
In diesen ersten Unterordnern (im Folgenden nur noch U1) können sich zig verschiedene Dateien
und weitere Unterordner beliebiger Tiefe befinden (z.B. D:\Daten\regionaltimes.com\Ordner1\Ordner2\Ordner3\Datei).
Mein Ziel ist es nun, sämtliche Dateien aus den Unterordnern in einem Batchlauf (oder auch mittels VBS) in die
entsprechenden U1 zu verschieben (die leeren Unterordner lösche ich später mit einem extra Batch, das habe ich
bereits gelöst). Leider habe ich bislang keine passende Lösung gefunden, da ein Vorgehen meiner Ansicht
nach ja wie folgt ablaufen müsste:

- öffnen des Ordners D:\Daten\
- Suchlauf durch alle U1, wobei der Ordnername U1 gemerkt werden müsste, da hierher ja später die Dateien
verschoben werden sollen
- U1 und sämtliche Unterordner nach *.* (alle Dateien) durchsuchen und diese dann mit move %1\*.* U1\*.* verschieben

Leider komme ich mit meinen Grundkenntnissen nicht wirklich weiter und habe wie gesagt auch noch nichts
passendes via google-Suche gefunden.
Vll. kann mir ja einer von den Profis hier helfen.
Vielen Dank schon mal im voraus.
Kommentar vom Moderator Biber am Aug 11, 2010 um 08:36:49 Uhr
Zitat von @00Snickers:am 11.08.2008
...in U1 liegt. Falls nein, dann move. Falls ja, dann die Datei umbennen in Dateiname + "_" + Inkrement.
Set /a rgc+=1
#696

Content-Key: 148406

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

Printed on: April 16, 2024 at 10:04 o'clock

Member: bastla
bastla Aug 05, 2010 at 10:55:31 (UTC)
Goto Top
Hallo 00Snickers und willkommen im Forum!

Die Frage bei allen derartigen Vorhaben ist immer: Wie soll bei Namensgleichheit von Dateien vorgegangen werden?

Ansonsten würde sich das (ungetestet) auf etwa
@echo off & setlocal
set "Basis=D:\Daten"  

for /d %%i in ("%Basis%\*.*") do (  
    pushd "%%i"  
    for /f "delims=" %%a in ('dir /s /b /a-d 2^>nul') do echo move "%%a"  
    popd
)
reduzieren ...

Das "echo" vor dem "move" soll ein gefahrloses Testen erlauben - ob mehrere gleichnamige Dateien in den Zielordner verschoben (und damit immer die jeweils bereits Vorhandenen überschrieben) würden, lässt sich damit aber nicht feststellen. Nur zur Sicherheit: Ein in einem Batch verwendetes "move" überschreibt ohne Rückfrage (entspricht dem Schalter "/Y")!

Grüße
bastla
Member: Biber
Biber Aug 05, 2010 at 11:11:26 (UTC)
Goto Top
Moin 00Snickers,

willkommen im Forum.
bastla hat sich ja schon der eigentlichen Frage angenommen.

Lass mich noch mal die Sinnhaftigkeit dieses Vorgehens hinterfragen.
Wenn du bisher eine Unterverzeichnisstruktur nach diesem Suchlauf vorliegen hast, dann hast du so oder so nach der Verschieberei einen Informationsverlust

a) weil die Verzeichnisstruktur fehlt und vielleicht einzelne Dateien in den Unterordnern nur in Verbindung mit anderen Dateien in der Unterverzeichnisstruktur interpretierbar sind
b) weil die Wahrscheinlichkeit, dass es keine Dateinamenskollisionen gibt weit unter dem IQ von Paris Hilton liegt. Und da musst diu dich dann zwangsweise von irgendwelchen Originaldaten trennen.

  • Wäre es nicht sinnvoller, die gesammelten Dateien Unterverzeichnisse mit Struktur und allen Dateien zusammenzudampfen mit Rar/Zip/7z/Zoo oder irgendeinem Packprogramm?

  • Und welche der Details deiner Sammelei brauchst du denn überhaupt jemals wieder und WTF wofür?

... irgendwie schimmert der große Plan des ganzen Unterfangens noch nicht so richtig durch.

Grüße
Biber
Member: 00Snickers
00Snickers Aug 05, 2010 at 12:34:12 (UTC)
Goto Top
Vielen Dank schon mal für die sehr schnelle Hilfe. Werde es gleich mal testen.

Um vll. etwas mehr Licht in die Sache zu bringen: Nach einem Suchlauf werden mit einem Programm
die Inhalte bestimmter Newsseiten gespeichert, daher die komischen Namen der ersten Unterordner.
Diese weisen jedoch je nach Aufbau der Homepage unterschiedliche Tiefen, usw. auf, weshalb die
benötigten Daten entweder direkt im ersten Unterordner oder eben im 20. liegen können. Eine Namensgleichheit
ist ausgeschlossen, da dies beim Speichern im Vorfeld bereits geprüft wird. Zumindest gilt das für diese eine Seite,
ob es bei mehreren der Fall ist wage ich zu bezweifeln, weshalb ich die Dateien ja auch nicht einfach nach
D:\Daten verschieben will, sondern in den jeweiligen Unterordner.

Ich hatte ja auch schon mit den Gedanken gespielt mir einfach die Namen der U1 auszulesen und neue Ordner mittels
md+NameU1+_neu anzulegen, dann die Daten aus allen Unterverzeichnissen dort hinzukopieren und dann die
leeren Ordner zu löschen. Aber 1. reichen da meine Kenntnisse ebenfalls nicht aus und 2. kann mans ja auch einfach
in die ersten Unterordner direkt kopieren.

Die Verzeichnisstruktur ist für mich vollkommen uninteressant. Es sollen zur weiteren vereinfachten Bearbeitung nur die relevanten Dateien direkt im ersten Unterordner zu finden sein und nicht Stunden mit der Suche (Klicken durch zig Ordnerebenen) nach der benötigten Datei (die ich nicht direkt suchen kann, da sowohl Name als auch die Dateiart ständig anders sind) verbracht werden.

Ich hoffe das war verständlich formuliert und es konnte etwas Licht ins Dunkel bringen.
Member: 00Snickers
00Snickers Aug 05, 2010 at 12:40:09 (UTC)
Goto Top
Was ich noch nicht verstehe ist, was die Eingabe " /a-d^>nul " in der Zeile
for /f "delims=" %%a in ('dir /s /b /a-d 2^>nul') do echo move "%%a" bewirkt.
Vielen Dank.
Member: bastla
bastla Aug 05, 2010 at 14:24:36 (UTC)
Goto Top
Hallo 00Snickers!
Was ich noch nicht verstehe ist, was die Eingabe " /a-d^>nul " ... bewirkt
Ohne die "2" wäre sie kontraproduktiv ... face-wink

Der Hilfe zu "dir" (also "dir /?") kannst Du entnehmen, dass mit "/a" bestimmte "Attribute" in das Ergebnis einbezogen / ausgeschlossen werden können - im konkreten Fall interessieren nur Dateien, aber keine "directories" = Ordner, deshalb das Minus.

Mit "2^>nul" werden etwaige Fehlermeldungen (gemeint ist damit vorrangig Datei nicht gefunden) unterdrückt (genauer: ins "Nichts" umgeleitet). Würde anstelle von "2" keine Angabe oder "1" verwendet, hätte das zur Folge, dass die "normalen" Ausgaben / Meldungen (hier also die eigentlich benötigten Pfade zu den Dateien) "verschwinden" würden.

Grüße
bastla
Member: 00Snickers
00Snickers Aug 11, 2010 at 08:10:55 (UTC)
Goto Top
Die "2" ging mir beim Kopieren wohl irgendwie verschütt face-wink

Vielen Dank für die sehr verständliche Erklärung, die mir gleich als Hilfe für ein anderes Problem verhalf face-smile
Der Batch funktioniert ebenfalls perfekt und ist genau so wie von mir ursprünglich gedacht!!

ABER nachdem nun schon gefragt wurde zwecks evtl. doppelt vorkommender Dateien (was zwar nicht der
Fall sein sollte bei diesem Problem, aber man weiß ja nie) wurde mein blöder Hang zum Verbessern und
Perfektionieren geweckt face-smile Was ich nun bislang erfolglos versuche ist eine Prüfung, ob nicht die Datei mit diesem
Namen bereits in U1 liegt. Falls nein, dann move. Falls ja, dann die Datei umbeNEnnen (man möge mir meinen faux pas bitte verzeihen face-wink ) in Dateiname + "_" + Inkrement.

Für eine evtl. Lösung oder Hilfe bin ich sehr dankbar. Sollte ich die Lösung unerwarteterweise doch noch selbst
finden, dann werde ich Sie natürlich hier posten. So oder so markiere ich im Anschluss daran den Post als gelöst.

Viele Grüße
00Snickers
Member: bastla
bastla Aug 11, 2010 at 19:32:39 (UTC)
Goto Top
Hallo 00Snickers!

Kombiniert mit einem Stückchen Code, das ich (ähnlich) schon mal an anderer Stelle verbrochen hatte (und daher gleich mal ungetestet hier einbaue face-wink), könnte das so aussehen:
@echo off & setlocal
set "Basis=D:\Daten"  

for /d %%i in ("%Basis%\*.*") do (  
    pushd "%%i"  
    for /f "delims=" %%a in ('dir /s /b /a-d 2^>nul') do call :ProcessFile "%%a"  
    popd
)
goto :eof

:ProcessFile
set "N=%~nx1"  
set Nr=1001
:Loop
    if not exist "%N%" goto :DoIt  
    set /a Nr+=1
    set "N=%~n1_%Nr:~-3%%~x1"  
goto :Loop
:DoIt
move %1 "%N%"  
goto :eof
Nach dem Motto "Nicht kleckern ..." gibt's die laufende Nummer gleich 3-stellig ... face-wink

Sicherung ist hier übrigens keine mehr enthalten - es wird gleich umbenannt (sonst ließen sich ja auch keine gleichnamigen Dateien im Ziel finden face-wink) ...
Plan B wäre übrigens, einfach den gesamten Pfad (durch "Entnahme" der "\") zum Namen zu machen (das Ergebnis wäre aber ziemlich unübersichtlich) ...

Grüße
bastla

P.S.:
man möge mir meinen faux pas bitte verzeihen face-wink
Da bist Du nun wirklich nicht der Erste (was Du ja Bibers "running gag counter" entnehmen kannst) ... face-wink
Member: 00Snickers
00Snickers Aug 12, 2010 at 08:36:24 (UTC)
Goto Top
Hallo Bastla,

erneut erstmal vielen Dank.

Hatte ebenfalls mit "IF NOT EXIST" geprüft und dann aber versucht mit "REN" die Dateien umzubenennen.
Ich merke schmerzlich, dass ich einfach viel zu viele Jahre nicht mehr programmiert habe face-sad

Die Lösung mit dem Aufruf von Funktionen finde ich da ja mal um Klassen besser als meinen Versuch alles nach dem "DO" reinzupacken. Nachdem ich mich schlau gemacht habe, was die mir unbekannten Teile wie "%~nx1" bewirken habe ich in vollster Vorfreude gleich mal ein paar Testläufe gestartet, aber leider funktioniert das Skript noch nicht bei mir.
Er kopiert nach wie vor alles in den ersten Unterordner (Top!), aber jetzt habe ich in den weiteren Unterordnern einfach Kopien von Dateien erstellt, welche dann z.B. in Test_1, Test_2 umbenannt werden sollten. Jetzt habe ich einfach ein paar "Echo" eingebaut, weil ich sehen wollte, ob er in die Schleife reingeht und die Namen richtig hat, aber mir wird nichts angezeigt.
Hier mein Versuch:

@ECHO OFF & SETLOCAL
 
SET "Basis=D:\download"   

FOR /d %%i IN ("%Basis%\*.*") DO (  
    PUSHD "%%i"   
    FOR /f "delims=" %%a IN ('dir /s /b /a-d 2^>nul') DO CALL :ProcessFile "%%a"  
    POPD 
    )
GOTO :eof

:ProcessFile 
SET ECHO "FileName=%~nx1"   
SET Counter=1001 
:Loop 
    IF NOT EXIST "%FileName%" GOTO :DoIt   
    SET /a COUNTER+=1 
    SET ECHO "FileName=%~n1_%Counter:~-3%%~x1"   
GOTO :Loop 
:DoIt 
MOVE %1 "%N%"   
GOTO :eof 

Was mir auffiel ist, dass der Aufruf von :Processfile mit der Übergabe von %%a stattfindet, aber die Definition der Funktion ohne Übergabeparameter ist. Spielt das eine Rolle, oder muss man bei der Batchprogrammierung einfach eine Variable übergeben und diese findet sich dann automatisch in der Funktion wieder?

Grüße
00Snickers

P.S. Ja, ich schäme mich immer noch, wo ich doch so viel Wert lege auf korrekte Schreibweise inkl. Groß- und Kleinschreibung...
Member: 00Snickers
00Snickers Aug 12, 2010 at 08:49:34 (UTC)
Goto Top
Da war ich wohl etwas vorschnell face-wink

Hab beim hier reinstellen (m)einen Fehler entdeckt und in Zeile 21. das "%N%" zu "%FileName" gemacht.
Nachdem ich die "ECHO" entfernt habe läufts wunderbar! Ein kleiner Wehrmutstropfen verbleibt allerdings noch:
Befindet sich in dem ersten Unterordner bereits eine Datei, dann lässt er diese nicht einfach stehen, sondern benennt
diese ebenfalls direkt mit "Dateiname" + "_" + "002" um.
Ansonsten bin ich sehr begeistert face-smile
Member: bastla
bastla Aug 12, 2010 at 09:16:20 (UTC)
Goto Top
Hallo 00Snickers!

Vorweg kurz zum Unterprogrammaufruf:
Der Teil ab ":ProcessFile" ist im Prinzip ein eigener Batch - deshalb kommen die Aufrufparameter auch als %1, %2, etc an (und benötigen keine eigene Deklaration). Beim zweiten "goto :eof" (entspricht einem "Return" eines [alten] Basic) wird das Unterprogramm beendet und es erfolgt die Rückkehr zum aufrufenden "Hauptprogramm". Das erste "goto :eof" sorgt schließlich für das Ende des Hauptprogrammes (damit nicht das Unterprogramm ein weiteres Mal durchlaufen wird).
Befindet sich in dem ersten Unterordner bereits eine Datei, dann lässt er diese nicht einfach stehen, sondern benennt diese ebenfalls direkt mit "Dateiname" + "_" + "002" um.
Stimmt - das liegt daran, dass ab diesem Unterordner (U1) alle (also auch die bereits unmittelbar in U1 liegenden Dateien) erfasst werden und die Datei "mit sich selbst" kollidieren würde - Abhilfe kann hier nur eine weitere Schleife über alle unter U1 liegenden Ordner schaffen - das müsste dann (weiterhin ungetestet) als neue Zeile 6 (oder, bei Dir, 7) so aussehen:
for /d %%u in (*.*) do for /f "delims=" %%a in ('dir /s /b /a-d "%%u" 2^>nul') do call :ProcessFile "%%a"
Grüße
bastla
Member: 00Snickers
00Snickers Aug 12, 2010 at 09:28:28 (UTC)
Goto Top
Hallo Bastla!

PERFEKT!!!!

Vielen herzlichen Dank! Funktioniert bestens. Danke für die Geduld und die hilfreichen Erklärungen,
damit kann ich auch allein einige weitere Probleme aufarbeiten. Gibt es hier sowas wie ein Bonuspunktesystem
für perfekte Lösungen? Falls ja, dann vergeb ich diese hiermit an Dich face-wink

Vielen Dank und "case closed"

Grüße
00Snickers
Member: bastla
bastla Aug 13, 2010 at 10:21:00 (UTC)
Goto Top
Hallo 00Snickers!

Schön, dass es passt face-smile
Gibt es hier sowas wie ein Bonuspunktesystem für perfekte Lösungen? Falls ja, dann vergeb ich diese hiermit an Dich face-wink
Gibt es nicht, aber ich freu' mich auch über die "ideellen" Punkte ... face-smile

Grüße
bastla