ultrasparc
Goto Top

Rekursives Löschen von Verzeichnissen wenn Dateien bestimmtes Alter erreicht haben

Hallo zusammen,

nun möchte ich doch die Gemeinde mal befragen. Nach dem x-ten Versuch habe ich immer noch keine brauchbare Lösung für dieses Problem. Wie so oft geht es um das Löschen von Daten in einem temporären Bereich nach einer bestimmen Zeit.
Aber.
Das Kriterium ist nicht das Datum einer Datei oder eines Verzeichnisses, sondern ergibt sich aus den jüngsten Dateien innerhalb einer Struktur. Ausgehend von einem Startverzeichnis (z.B. c:\temp) sollen alle Verzeichnisse gelöscht werden, in denen es seit n Tagen keine Änderung gab. Jetzt kann es aber beliebig viele Unterverzeichnisse geben, mit wieder beliebig vielen Unterverzeichnissen,...
Eine Datei oder ein Verzeichnis in irgend einem der Unterverzeichnisse mit einem kleineren n muss das Löschen des ganzen Zweiges (nach oben hin gesehen) verhindern.

Also anders formuliert, ein Script (oder der Ansatz zu einem) wird gesucht, das ein Verzeichnis nur löscht (rekursiv), wenn es in ihm keine Dateien oder Verzeichnisse gibt, die jünger sind als ein Anzahl von Tagen n.

Hoffentlich kann meiner Beschreibung jemand folgen...

Ultrasparc

Content-Key: 94397

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

Ausgedruckt am: 29.03.2024 um 01:03 Uhr

Mitglied: bastla
bastla 14.08.2008 um 14:04:31 Uhr
Goto Top
Hallo Ultrasparc und willkommen im Forum!

Etwas zum Testen:
'DOF.vbs  
Alter = 10 'Anzahl der Tage  
StartOrdner = "C:\Temp"  
If WScript.Arguments.Count > 0 Then StartOrdner = WScript.Arguments(0)
LogDatei = StartOrdner & "\Log.txt" 'verhindert Löschen des Startordners  
'LogDatei = "D:\Log.txt"  

Set fso = CreateObject("Scripting.FileSystemObject")  
Set L = fso.CreateTextFile(LogDatei, True)

Heute = Date()
L.WriteLine "Löschen mit Alter von mehr als " & Alter & " Tagen (= jüngstem Änderungsdatum vor " & Heute - Alter & ")"  
L.WriteLine
DeleteInFolder fso.GetFolder(StartOrdner)
L.Close
WScript.Echo "Fertig."  

Sub DeleteInFolder(Ordner)
For Each Unter In Ordner.SubFolders
	DeleteInFolder(Unter)
Next
WegDamit = True
If Ordner.SubFolders.Count > 0 Then
	WegDamit=False
	L.WriteLine "## """ & Ordner.Path & """ enthält Unterordner. ##"  
Else
	For Each Datei In Ordner.Files
		L.WriteLine Heute - Int(Datei.DateLastModified) & vbTab & Datei.DateLastModified & " """ & Datei.Path & """"  
		If Datei.DateLastModified > (Heute - Alter) Then
			WegDamit = False
			Exit For
		End If
	Next
End If
If WegDamit Then
	L.WriteLine "--- """ & Ordner.Path & """ wird gelöscht. ---"  
	Ordner.Delete(True)
Else
	L.WriteLine "+++ """ & Ordner.Path & """ wird nicht gelöscht. +++"  
End If
End Sub
Dieses VBScript erwartet die Übergabe eines Startverzeichnisses (zB per Drag & Drop) bzw verwendet alternativ das Default-Verzeichnis lt Zeile 3. (Derzeit wird noch nicht überprüft, ob das Startverzeichnis existiert.)

Wird die Logdatei im Startverzeichnis erstellt, bleibt dieses auf jeden Fall erhalten; falls dies nicht gewünscht ist, kann die Zeile 4 durch die Zeile 5 (ohne das Apostroph am Anfang) mit der Angabe eines anderen Pfades ersetzt werden.

Um gefahrlos testen zu können, kannst Du die Zeile 37
Ordner.Delete(True)
durch ein vorangestelltes Apostroph "entschärfen" - allerdings werden dann in der Struktur höher liegende Verzeichnisse natürlich immer als "nicht zu löschend" angegeben, da ja die Unterverzeichnisse auf jeden Fall erhalten bleiben (was bei aktiver Löschfunktion nur der Fall wäre, wenn diese tatsächlich jüngere Dateien enthielten).

Leere Verzeichnisse werden (im Ernstfall) immer gelöscht, da sich darin ja keine "erhaltenswerte" Datei befindet.

Grüße
bastla
Mitglied: Ultrasparc
Ultrasparc 14.08.2008 um 16:03:08 Uhr
Goto Top
Vielen Dank erst einmal.

Manche Probleme kann man wohl nicht mit vertretbarem Aufwand in reiner Batch lösen (ich jedenfalls nicht).

Na egal. Ein erster Test in einem neu angelegten Verzeichnis sieht gut aus, im Logfile steht das, was ich erwartet hätte.
Ich werde jetzt noch eine Kopie eines der Verzeichnisse mit richtigen Daten machen und ein paar Kommentare im Script nachrüsten.

Testlauf und Info dann aber sicher erst morgen Früh...

Ultrasparc - wo es kein *.vbs gibt face-wink
Mitglied: Ultrasparc
Ultrasparc 15.08.2008 um 07:52:05 Uhr
Goto Top
So, da bin ich wieder.

Der Test mit den kopierten Live-Daten hat noch eine Kleinigkeit ergeben: Der Timestamp des Ordners wird nicht beachtet.

Beispiel: die Struktur wird durch Kopieren erzeugt, die Ordner bekommen also einen neuen Timestamp. Die Dateien nicht. Der Ordner (und die Files/Ordner in ihm) dürfen dann nur gelöscht werden, wenn auch der Ordner selbst entsprechend alt ist.

Es sollte ja auch 'DateLastModified' an dem zu prüfenden Unterordner geben, aber ich bekomme den nicht mal angezeigt (habe ich erwähnt, das ich kein VB kann?). Versucht habe ich es vor Zeile 20 - wenn er zu jung ist, braucht man ja gar nicht rein zu gehen.

Ultrasparc
Mitglied: bastla
bastla 15.08.2008 um 10:05:15 Uhr
Goto Top
Hallo Ultrasparc!

Entsprechend Deinem Beispiel müsste dann aber bei Ordnern das Erstellungsdatum zum Kriterium gemacht werden - dazu die Zeilen 19-21 durch
For Each Unter In Ordner.SubFolders
	L.WriteLine "## " & Heute - Int(Unter.DateCreated) & vbTab & Unter.Created & " """ & Unter.Path & """ ##"  
	If Unter.DateCreated <= (Heute - Alter) Then
		DeleteInFolder(Unter)
	Else
		L.WriteLine "+++ """ & Unter.Path & """ wird nicht gelöscht. +++"		  
	End If
Next
ersetzen.

Allerdings stellt sich mir die Frage, was einen neuen Ordner mit alten Daten erhaltenswert macht ...

Grüße
bastla
Mitglied: Ultrasparc
Ultrasparc 15.08.2008 um 10:38:56 Uhr
Goto Top
Hallo bastla,

kann ich ganz leicht erklären. Das ist quasi eine Projekt-Struktur. Verschiedene Ordner werden nur gelesen, ohne geht es aber nicht.
Es hängt aber von den jeweiligen Änderungen ab, wo gelesen und wo geschrieben wird. Und wenn eine Datei in einem Ordner geändert wird, ändert sich ja das Datum des Ordners auch.

Ich glaube deshalb, das ein 'DateCreated' nicht das Passende ist.
Kann ich das einfach mit 'DateLastModified' ersetzen?

Ultrasparc
Mitglied: bastla
bastla 15.08.2008 um 10:44:32 Uhr
Goto Top
Hallo Ultrasparc!

Kann ich das einfach mit 'DateLastModified' ersetzen?
Wenn Du das Risiko eingehen willst, dass ein Ordner nicht gelöscht wird, weil gestern eine Datei darin gelöscht wurde und daher sein Änderungsdatum auf gestern steht ...

Größer ist das Risiko durch Verwendung von "DateCreated" aber eigentlich auch nicht - es wird ja hier nicht gelöscht, wenn das Erstellungsdatum neu genug ist, anderenfalls werden aber ohnehin die Inhalte noch überprüft.

Grüße
bastla
Mitglied: Ultrasparc
Ultrasparc 15.08.2008 um 12:06:45 Uhr
Goto Top
Hallo bastla,

genau so soll es sein, das Löschen einer Datei ist eine Bearbeitung (der User macht da also noch was). Also nicht Löschen.
Ich versuche es noch mal anders darzustellen:
startdir\dir1a\dir1b\dir1c\dat1
              \dir2b\dat2
              \dat3

Wenn unter dir1a etwas <= n ist (also dir1b, dir2b, dir1c, dat1, dat2 oder dat3 ), darf nichts unter dir1a gelöscht werden.

Leider hat das Einsetzen der Zeilen nicht zu einer Veränderung geführt. Keine der WriteLine Zeilen stehen im Logfile.

So sieht das jetzt aus:
Sub DeleteInFolder(Ordner)
For Each Unter In Ordner.SubFolders
	L.WriteLine "#### " & Heute - Int(Unter.DateCreated) & vbTab & Unter.Created & " """ & Unter.Path & """ ####"  
	If Unter.DateCreated <= (Heute - Alter) Then
		DeleteInFolder(Unter)
	Else
		L.WriteLine "++++ """ & Unter.Path & """ wird nicht gelöscht. ++++"		  
	End If
Next
WegDamit = True
...

Habe ich was falsch gemacht?

Ultrasparc
Mitglied: bastla
bastla 15.08.2008 um 13:05:14 Uhr
Goto Top
Hallo Ultrasparc!

Keine der WriteLine Zeilen stehen im Logfile.
Es müsste in Deiner der Zeile 3 "Unter.DateCreated" heißen, und eigentlich solltest Du eine Fehlermeldung erhalten haben ...

Mit der folgenden Alternative könntest Du übrigens beide Daten ausgeben und auch für die Entscheidung, ob ein Unterverzeichnis überhaupt näher untersucht werden muss, berücksichtigen:
	L.WriteLine "#### " & Heute - Int(Unter.DateLastModified) & vbTab & Unter.DateLastModified & " **" & Heute - Int(Unter.DateCreated) & "_" & Unter.DateCreated & "** """ & Unter.Path & """ ####"  
	If Unter.DateCreated <= (Heute - Alter) And Unter.DateLastModified <= (Heute - Alter) Then

Grüße
bastla
Mitglied: Ultrasparc
Ultrasparc 15.08.2008 um 15:36:09 Uhr
Goto Top
Hallo bastla,

ich habe das jetzt so weit korrigiert und am Laufen. Die Abfrage nach den Dateien ist auskommentiert. Meldungen kommen auch alle im Log.

Aber wenn ich Dich noch mal kurz in meinen letzten Beitrag bitten darf, der Absatz unter dem ersten Code - das geht eben nicht.
In dem Beispiel würde dir1c und dat1 gelöscht (wenn >= n), obwohl dir2b noch <= n ist. So soll es halt nicht sein.
Wahrscheinlich ist noch ein Art Level-Variable notwendig. Ich versuche mich da weiter.

Trotzdem vielen Dank, hast mir schon viel geholfen.

Ultrasparc
Mitglied: bastla
bastla 15.08.2008 um 16:29:39 Uhr
Goto Top
Hallo Ultrasparc!

Soferne ich Dich jetzt (endlich) ganz richtig verstehe, hieße das ja eigentlich, es müssten im Fall des Falles immer nur die unmittelbaren Unterverzeichnisse des Startverzeichnisses gelöscht werden - richtig?

Grüße
bastla
Mitglied: Ultrasparc
Ultrasparc 15.08.2008 um 17:31:32 Uhr
Goto Top
Hallo bastla,

ja, das ist absolut korrekt. Ich lasse damit zwar Sachen liegen, aber ich hätte einen mit at zu startenden Job, der mir nachts keinen Blödsinn macht.
Hast Du eine Idee, wie man so etwas umsetzt?

Für Sonderfälle kann ich ja per Hand auf ein Unterverzeichnis starten. Die User sind da sehr erfinderisch, was die Ablage von Daten angeht.


Ultrasparc
Mitglied: bastla
bastla 15.08.2008 um 18:54:38 Uhr
Goto Top
Hallo Ultrasparc!

Da Du Dich als Batchfan deklariert hast, eine andere Version (mit gaaaanz wenig VBS face-wink):
@echo off & setlocal enabledelayedexpansion
set "Startverzeichnis=C:\Temp"  
set Alter=10

set S=%temp%\Stichtag.vbs
>%S% echo D=WScript.Arguments(0):N=DateAdd("d",WScript.Arguments(0),Date):WScript.Echo Right(N,4)^&Mid(N,4,2)^&Left(N,2)  
for /f %%i in ('cscript //nologo %S% -%Alter%') do set "Stichtag=%%i"  
if not defined Stichtag echo Fehler bei Tageberechnung & goto :eof

echo Stichtag:  %Stichtag%  bei Alter:  %Alter%
echo\
for /d %%i in ("%Startverzeichnis%\*.*") do call :Verzeichnis "%%i"  
goto :eof

:Verzeichnis
echo ====================================================================
set Behalten=
echo  %~t1 %1
for /f "tokens=1-3 delims=. " %%a in ("%~t1") do if %%c%%b%%a geq %Stichtag% set Behalten=True & goto :VerzeichnisFertig  
for /f %%f in ('dir /s /b /ad %1') do if not defined Behalten (  
    if "%%~tf" neq "" (  
	    echo  %%~tf "%%f"  
	    for /f "tokens=1-3 delims=. " %%a in ("%%~tf") do if %%c%%b%%a geq %Stichtag% set Behalten=True  
		) else (
	    set "Parent=%%~dpf"  
		for /f "tokens=1-3 delims=. " %%a in ('dir /tc /ad "!Parent!"^|findstr /e c:"%%nxf"') do (  
            echo  %%a.%%b.%%c "%%f"  
			if %%c%%b%%a geq %Stichtag% set Behalten=True
		)
	)
)
:VerzeichnisFertig
if not defined Behalten goto :WegDamit
echo --------------------------------------------------------------------
echo ++++ %1 wird nicht entfernt. ++++
echo ====================================================================
echo\
goto :eof

:WegDamit
echo --------------------------------------------------------------------
echo #### %1 wird entfernt. ####
echo ====================================================================
echo\
::rd /s /q %1
goto :eof
Lt Erfahrungswerten (und http://support.microsoft.com/kb/299648/de face-wink) müsste es eigentlich genügen, das Erstellungsdatum nur dann zu überprüfen, wenn es in dem Ordner keine Dateien gibt/gegeben hat (in diesem Fall liefert "%%~tf" auch kein Änderungsdatum).

Grüße
bastla
Mitglied: Ultrasparc
Ultrasparc 15.08.2008 um 20:04:46 Uhr
Goto Top
Hallo bastla,

bei Batch muss ich nicht so viele dumme Fragen stellen - stimmt, aber wenn ich dann hier immer sehe, wie die Zeilen aus dem Ärmel geschüttelt werden - Hut ab.
Auch wenn ich etwas ähnliches zustande gebracht habe, bei der Rechnerei mit den Zeiten habe ich mich verrannt. Von der Zeit, die ich gebraucht habe mal ganz abgesehen.

Ich danke wieder für die uneigenützige Hilfe, am Montag hänge ich mich wieder ran.
Schönes Wochenende.

Ultrasparc
Mitglied: Ultrasparc
Ultrasparc 18.08.2008 um 16:09:14 Uhr
Goto Top
Hallo bastla,

da bin ich wieder.
Was mir beim Lesen gleich augefallen ist: kleiner Fehler in Zeile 2 - da ist das Hochkomma verutscht, richtig wäre natürlich
set Startverzeichnis="C:\Temp"  
Falls jemand mitliest.
...
So, die letzten Zeilen stammen von 6:20, bis jetzt gab es immer Wichtigeres zu tun. Aber jetzt.
Es tut, prima. Habe zwei Verzeichnisse gesäubert. Nur kleine Optimierungen wie z.B. Löschen von Leeren Ordner, auch wenn sie noch zu jung sind. Und schreiben in ein Log und so Sachen.

Nochmals vielen Dank.

Ultrasparc
Mitglied: bastla
bastla 18.08.2008 um 16:15:41 Uhr
Goto Top
Hallo Ultrasparc!

Was mir beim Lesen gleich augefallen ist: kleiner Fehler in Zeile 2 - da ist das Hochkomma verutscht
Freut mich, dass Du so genau liest, allerdings (für alle Mitleser face-wink) ist diese Schreibweise Absicht und erzeugt keinen Fehler, sondern sorgt einerseits dafür, dass der Inhalt der Variablen genau festgelegt wird (und nicht zB Leerzeichen am Ende des Textes mit aufgenommen werden), und dass andererseits die Variable selbst keine Anführungszeichen enthält - letztere kann ich so genau dort, wo ich sie benötige, setzen ...

Grüße
bastla
Mitglied: Ultrasparc
Ultrasparc 18.08.2008 um 17:59:25 Uhr
Goto Top
ok, merke ich mir...

Ultrasparc