Tiefe Ordnerstrukturen untersuchen und verarbeiten mit Batch (2019)

marc-olivier-jodoin-0TB3AiOu2g4-unsplash

Kürzlich fragte mich Blogbesucher Sebastian nach Hilfe: Mittels Batch-Skript sollen innerhalb eines Ordners, in einer bestimmten Unterordnertiefe, bestimmte Ordner umbenannt werden. In dem Artikel des Kommentars hatte ich Hilfestellung gegeben, bestimmte Aktionen auf alle Unterordner eines Ordners auszuführen. Die Einschränkung, diese Aktionen nur auf ein bestimmten Level von Unterordnern auszuführen, gab es nicht. Schauen wir uns das mal an.

Auslesen von tiefen Ordnerstrukturen

Die Grundstruktur bleibt erstmal gleich: Mit for /d in ([order]\*) do () werden Befehle auf alle Unterordner eines Ordners ausgeführt. Mit dem zusätzlichen Parameter /r durchsuchen wir rekursiv tiefe Ordnerstrukturen und ignorieren sogar Dateien für mehr Performance.

batch-deep-recursion-folder-manipulation-tiefe-ordnerstrukturen-bearbeiten-ausgabe
Mit for /d /r tiefe Ordnerstrukturen durchlaufen und ausgeben

Der Befehl wird dann leicht umgebaut: for /d /r "[ordner]" %%i in (*) do ()
Dann noch etwas Ausgabe mit dazu und wir haben fast den tree Befehl nachgebaut 😉

@echo off
setlocal enableDelayedExpansion 

for /d /r "%cd%" %%i in (*) do (
	echo %%i
)
pause
endlocal

Erkennung der Tiefe des aktuellen Ordners

Jetzt brauchen wir eine Erkennung der Tiefe. Das hat mich etwas länger beschäftigt als gedacht.
An die Tiefe der Rekursion von for /d /r scheint man leider nicht zu kommen und mehrere nicht-rekursive for-Schleifen ineinanderschachteln ist zu unflexibel. Stattdessen war folgender späterer Gedanke attraktiv einfach: Die Backslashes im Ordnerpfad zählen und damit die Tiefe erkennen.
Etwas sehr simpel aber das einzige, das ich erfolgreich umsetzen konnte. Wer hier einen besseren Ansatz hat, gerne ein Kommentar hinterlassen.

Das Zählen von Zeichen in einem String ist in Batch leider kein Einzeiler, aber das Rad muss ja nicht neu erfunden werden. Hier hat schonmal jemand eine Funktion dafür geschrieben. Möglich wäre auch die Nutzung von Powershell mit dem [string].split() Befehl, jedoch ist die Nutzung von Powershell in Batch ein Fass, dass wir hier jetzt nicht öffnen.

Auch interessant:  Windows: Mit RestrictRun eine Programme ausschließlich erlauben oder blockieren

Nun zählen wir für jeden Unterordner die Backslashes, subtrahieren die Anzahl der Backslashes des Ordners, in dem das Skript ausgeführt wird und erhalten damit die relative Tiefe zum Skriptordner.

@echo off
setlocal enableDelayedExpansion 

set startdir=%cd%

call :GetCharCount startLevel %startdir% \

for /d /r "%cd%" %%i in (*) do (
	echo %%i
	call :GetCharCount level %%i \
	echo absolute Tiefe: !level!
	set /a relLevel=!level!-!startLevel!
	echo relative Tiefe: !relLevel!
)
pause
endlocal

:GetCharCount
  set _S=%~2
  set /a %~1 = 0
  for /L %%i in (0,1,10000) do (
    if "!_S:~%%i,1!"=="" (set "_S=" & exit /b)
    if /i "!_S:~%%i,1!"=="%~3" set /a %~1 += 1
  )
  set "_S="
  exit /b
batch-deep-recursion-folder-manipulation-tiefe-ordnerstrukturen-bearbeiten-tiefe-ausgeben
Absolute und relative Tiefe zum Skriptordner errechnen und ausgeben.

Verarbeitung von Ordnern in Abhängigkeit von Bedingungen

So, nun kann die Logik in Abhängigkeit von der Tiefe und weiteren gewünschten Faktoren mit ifs verbaut werden.
Alle Ordner in der Tiefe X UND mit dem Ordnernamen Y sollen umbenannt werden? Ich habe das beispielhaft (mit viel debug output) mal umgesetzt:

@echo off
setlocal enableDelayedExpansion 

set startdir=%cd%
set renameFrom=BitteUmbenennen
set renameTo=NeuerOrdnername
call :GetCharCount startLevel %startdir% \

for /d /r "%cd%" %%i in (*) do (
	echo ----
	echo %%i
	call :GetCharCount curLevel %%i \
	set /a relLevel=!curLevel!-!startLevel!
	for %%J in (%%i) do set foldername=%%~nxJ
	echo absolute Tiefe: !curLevel!
	echo relative Tiefe: !relLevel!
	echo Ordnername: !foldername!
	if !relLevel!==3 if "!foldername!"=="!renameFrom!" (
		echo **** RENAME ****
		set oldPath=%%i
		set newPath=!oldPath:%renameFrom%=%renameTo%!
		echo !newPath!
		move !oldPath! !newPath!
		echo ****
	)
)
pause
endlocal

:GetCharCount
  set _S=%~2
  set /a %~1 = 0
  for /L %%i in (0,1,10000) do (
    if "!_S:~%%i,1!"=="" (set "_S=" & exit /b)
    if /i "!_S:~%%i,1!"=="%~3" set /a %~1 += 1
  )
  set "_S="
  exit /b
batch-deep-recursion-folder-manipulation-tiefe-ordnerstrukturen-bearbeiten-umbenennen
Tiefe Ordnerstrukturen werden durchsucht und (beispielhaft) abhängig von der Tiefe und dem Ordnernamen umbenannt

Das ist jetzt natürlich beliebig erweiterbar aber das Prinzip sollte klar werden. Mehrere Voraussetzungen können einfach durch aneinanderreihen von ifs geprüft werden, quasi eine Einzeiler-Verschachtelung. Den aktuellen Ordnernamen ziehen wir mittels for-Befehl raus. Den neuen Ordnernamen bauen wir dank Batch String Manipulation. Das wäre in Powershell vermutlich ein Fünfzeiler aber sowas sieht in Batch irgendwie immernoch „schön“ aus 😉

Auch interessant:  AD GPO: Erweiterte Filterung mit WMI

@Sebastian: Ich hoffe, deine Anfrage ist damit erfolgreich beantwortet und du kannst den Code so für deine Zwecke einsetzen. Sag Bescheid, wenn du noch Hilfe brauchst.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.