rekario
Goto Top

Dateien in einer Verzeichnisstruktur mit Ordnern und Unterordnern per Batch nach entsprechenden Ordnernamen benennen

Hallo liebe Administrator-Gemeinde,

ich wende mich heute an euch, da sich mir ein Problem aufgetan hat, dessen Lösung ich nicht alleine nachkomme - Überraschung.

Für mich ist Batch ein Neuland und ich habe auch so nicht wirklich viel Wissen in Scripting, dem Gebiet an sich, etc. lediglich etwas C++ - aber das ist ein anderes Thema, natürlich bin stets bereit mein Wissen zu erweitern, doch da ich für meine aktuelle Aufgabe eine schnelle und möglichst unkomplizierte Lösung benötige, mangelt es mir an Zeit und Möglichkeiten im Thema Batch von Grund auf einzuarbeiten - das wird später folgen.

Nun ja, lange Rede, kurzer Sinn, die Situation sieht folgendermaßen aus:
Ich lasse mir per Batch eine Ordnerstruktur erstellen, in denen sich viele Ordner, mit Unterordnern, die widerum Unterordner haben, etc. erstellen.
In jedem dieser Ordner wird eine .txt-Datei mit Inhalt erstellt.
Zusätzlich werden eine .docx, .pptx und eine .xlsx-Datei in jedes Verzeichnis kopiert - und ab hier wird es spannend.

Das kopieren übernehme ich mit folgender Code-Zeile:
for /f "delims=" %%i in ('dir /a-d /b /s "C:\Pfad\*.txt"') do copy "C:\Pfad\test.pptx" "%%~dpi"  
Ich durchsuche also jeden Pfad, in dem ich zuvor eine .txt-Datei angelegt habe und kopiere dann entsprechend die .pptx-Datei in diesen (für .docx und .xlsx gibt es denselben Befehl).

Nun habe ich also halb Google durchgewühlt und bin zu ein paar interessanten Lösungsansätzen gekommen, um die "test.pptx" in den Ordnernamen des Verzeichnisses, in dem sie sich befindet umzubenennen, eine davon hier im Forum: Dateien nach Ordner umbenennen.
Dort sieht der Code folgendermaßen aus:
@echo off

setlocal


set "SrcDir=E:\test"  

for /d %%d in ("%SrcDir%\*.*") do (  
  set "ActDir=%%d"  
  call :ProcessDir
)

exit /b



:ProcessDir
  for /f "delims=" %%f in ("%ActDir%") do set "ParentDir=%%~nxf"  

  for /f "delims=" %%f in ('dir /b /a:-d "%ActDir%" 2^>NUL') do (  
    set "Item=%%~xf"  
    call :ConcatString Extensions
  )

  for %%e in (%Extensions%) do (
    set /a Cntr=1
    set "Ext=%%e"  

    for /f "delims=" %%f in ('dir /b /o:-s /a:-d "%ActDir%\*%%e" 2^>NUL') do (  
      set "File=%ActDir%\%%f"  
      call :RenameFile
      set /a Cntr+=1
    )
  )
exit /b



:RenameFile
  ren "%File%" "%ParentDir%-%Cntr%%Ext%"  
exit /b



:ConcatString
  call set "Compare1=%%%1%%"  
  call set "Compare2=%%%1:%Item%=%%"  
  if "%Compare1%" neq "" if "%Compare1%" neq "%Compare2%" exit /b  
  call set "%1=%%%1%% %%Item%%"  
exit /b

Funktioniert auch... Jedoch geben sich zwei Probleme auf:
1. Die Dateien in den Unterverzeichnissen bleiben unberührt!
2. Die schon vorhandenen .txt-Dateien sowie die betroffenen .docx / .pptx / .xlsx-Dateien erhalten alle die Endung -1.

Da ich wie gesagt anfänger in dem Thema bin, habe ich versucht ein paar kleine Änderungen vorzunehmen, die mir allerdings das Script zerschossen haben, ich bitte deshalb um Hilfe / Lösungen!

Vielen Dank im Voraus! =)

Content-Key: 286458

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

Printed on: April 19, 2024 at 21:04 o'clock

Member: Friemler
Solution Friemler Oct 23, 2015, updated at Oct 26, 2015 at 07:16:09 (UTC)
Goto Top
Hallo Rekario,

das obige Script ist für Deine Anforderungen viel zu kompliziert. Probiere mal folgendes (ungetestet):
@echo off & setlocal

for /f "delims=" %%i in ('dir /a-d /b /s "C:\Pfad\*.txt"') do (  
  call :ProcessDir "%%~dpi"  
)

exit /b 0


:ProcessDir
  set "CurDir=%~1"  
  set "CurDir=%CurDir:~0,-1%"  

  for /f "delims=" %%j in ("%CurDir%") do (  
    echo copy "C:\Pfad\test.docx" "%CurDir%\%%~nxj.docx"  
    echo copy "C:\Pfad\test.xlsx" "%CurDir%\%%~nxj.xlsx"  
    echo copy "C:\Pfad\test.pptx" "%CurDir%\%%~nxj.pptx"  
  )
exit /b 0

Der Code ist noch nicht "scharf geschaltet", dazu musst Du die ECHO-Befehle in den Zeilen 15-17 entfernen.

Gruß
Friemler
Member: Rekario
Rekario Oct 26, 2015 updated at 08:36:55 (UTC)
Goto Top
Hallo Friemler,

vielen Dank für die schnelle Antwort und entschuldige das ich mich erst jetzt melde, Tele2 hat seit Samstag einen Serverausfall was mich Zuhause um mein Internet gebracht hat ~ wie dem auch sei, ich habe es eben mal probiert und es funktioniert einwandfrei! face-smile

Tausend dank dafür!

Bestünde die Möglichkeit, das du die wichtigsten Bausteine kurz erläuterst? face-smile

Gruß,
Rekario

EDIT
Eine kleine "Schönheitsgeschichte" hätte ich noch, ich habe das Script jetzt bei mir eingepflegt, nach dem kopieren beendet es das sich jedoch automatisch, obwohl ich noch eine weitere "Aufgabe" habe, die nachfolgend kommt, durch das entfernen der "exit" kopiert es nicht mehr in alle Pfade, es wäre kein Problem das ich meinen letzten "Scriptblock" nach vorne verschiebe, jedoch wüsste ich gerne, wie ich in einem solchen Fall dafür sorge, das nachfolgende Scriptbausteine noch ausgeführt bzw. das Script an sich nicht beendet wird? face-smile
Member: Friemler
Solution Friemler Oct 26, 2015 updated at 11:44:08 (UTC)
Goto Top
Hallo Rekario,

natürlich erkläre ich gerne die Funktionsweise des Scripts.

Die Zeilen 3-5 stellen das Hauptprogramm dar, der Abschnitt in den Zeilen 10 (:ProcessDir) bis 19 (exit /b 0) ist ein Unterprogramm. Die Aufteilung ist wegen einer Beschränkung von Batchscript nötig, dazu komme ich gleich.

Im Hauptprogramm wird Deine vorher angelegte Verzeichnisstruktur nach Ordnern durchsucht, die eine txt-Datei enthalten. Für jeden Fund wird in Zeile 4 das Unterprogramm ProcessDir aufgerufen, dabei wird der vollständige Pfad des gerade aktuellen Verzeichnisses als Argument übergeben. Das wird durch das Konstrukt %%~dpi erreicht. Damit wird aus dem vollständigen Pfad zur txt-Datei, der in der FOR-Laufvariablen %%i enthalten ist, das Laufwerk (Drive => d) und der Pfad (Path => p) extrahiert.

Allerdings bleibt der Backslash zwischen dem letzten Verzeichnis des Pfades und dem Namen der txt-Datei erhalten, aus z.B. "C:\Der\Pfad\zur\Datei\DieDatei.txt" wird also "C:\Der\Pfad\zur\Datei\" (natürlich jeweils ohne die Anführungszeichen). Um den abschließenden Backslash zu entfernen, muss dieser String in eine normale Batchscript-Variable umgepackt werden, weil für FOR-Laufvariablen der entsprechende Operator nicht zur Verfügung steht.

Das Umpacken und die Weiterverarbeitung in einer normalen Variable geht nur, wenn man die verzögerte Variablenerweiterung aktiviert (die ich persönlich immer zu umgehen versuche) oder ein Unterprogramm verwendet, wie im obigen Fall.

Eigentlich müsste man ja das Unterprogramm in die FOR-Schleife integrieren. Der Batchscript-Interpreter behandelt aber alles innerhalb der FOR-Schleife als eine einzige Zeile und ersetzt bei deaktivierter verzögerter Variablenerweiterung (der Normalfall) alle normalen Batchscript-Variablen vor der Verarbeitung einer Zeile durch ihren aktuellen Wert. Variablen, die ihren Wert erst innerhalb der Schleife erhalten, haben vor dem Durchlauf der Schleife entsprechend keinen Wert, der Code würde deshalb nicht wie gewünscht funktionieren.

In einem Unterprogramm kann man jedoch wieder ganz normal mit Batchscript-Variablen arbeiten. In Zeile 11 wird mit set "CurDir=%~1" der Variablen CurDir der Wert des ersten an das Unterprogramm übergebenen Arguments zugewiesen und durch die Tilde evtl. umschließende Anführungszeichnen entfernt. Durch das Konstrukt %CurDir:~0,-1% wird das letzte Zeichen des Strings entfernt, in unserem Fall also der Backslash.

Die FOR-Schleife in den Zeilen 14-18 ist nur notwendig, um den Inhalt der Variablen CurDir wieder in eine FOR-Laufvariable zu bekommen, weil nur für diese Variablenart die Operatoren zur Pfadzerlegung zur Verfügung stehen (und wegen diesem ganzen Hick-Hack ist Batchscript ein wahres Minenfeld, bei der Einarbeitung in das Thema kommt man aus dem Kopfschütteln nicht mehr heraus). In den Zeilen 15-17 wird mit dem Konstrukt %%~nxj aus dem Wert der FOR-Laufvariablen %%j der Name (n => Name) und die Erweiterung (x => Extensions) des letzten Pfadbestandteils extrahiert. Aus z.B. "C:\Der\Pfad\zur\Datei" wird also "Datei", was ja der gewünschte Name für die zu kopierenden Dateien im Zielverzeichnis ist.

Um das vorzeitige Beenden Deines Scripts zu vermeiden, verschiebe das Unterprogramm ProcessDir incl. des exit /b 0 von Zeile 7 ans Ende der Scriptdatei, hinter Deinen eigenen Code. Das exit /b 0 beendet das Hauptscript und verhindert somit, dass nach dessen Abschluss das Unterprogramm ProcessDir nochmals ausgeführt wird. Das exit /b 0 in Zeile 19 hingegen beendet nur das Unterprogramm ProcessDir.

Um Dich in das Thema FOR-Schleifen und verzögerte Variablenerweiterung einzuarbeiten, empfehle ich Dir mein Tutorial zur FOR-Schleife.

Grüße
Friemler
Member: Rekario
Rekario Oct 26, 2015 at 11:49:00 (UTC)
Goto Top
Hey Friemler!

Vielen Dank - erneut! Du hast mir ein weiteres mal sehr geholfen, danke auch für die ausführliche Erklärung. Sobald ich etwas Luft habe, werde ich mich Intensiv mit dem Thema beschäftigen - deshalb hier auch ein großes Danke für den Link, ich habe mal Stichprobenartig ein bisschen was daraus gelesen, du hast das echt äußerst ausführlich und umfangreich verfasst!

Dankeschön! face-smile