Wie man/frau ein (Batch-)Programm schreibt

Diskutiere Wie man/frau ein (Batch-)Programm schreibt im Programmierung Forum im Bereich Software Forum; Hi Die Systemfunktionen des Kommandointerpreters sind hilfreich und nuetzlich fuer alle moeglichen Aufgaben, aber leider schlecht bis gar nicht...
M

Mial

Threadstarter
Mitglied seit
14.07.2004
Beiträge
2.132
Hi

Die Systemfunktionen des Kommandointerpreters sind hilfreich und nuetzlich fuer alle moeglichen Aufgaben, aber leider schlecht bis gar nicht dokumentiert. Das stellt viele Anwender immer wieder vor scheinbar unloesbare Probleme, wie z.B. der Thread "Dateien per Batch löschen, die älter als zwei Tage sind" zeigt. Deshalb wage ich an diesem Beispiel mal einen kleinen Versuch, ein wenig Licht ins Dunkel der Batchprogrammierung zu bringen. :blush

Das fertige Programm ist natuerlich auch in einem Zip-File zum Download am Ende dieses Postings angefuegt. :hehe

Dieses Batchprogramm soll also ausgewaehlte Dateien loeschen und unter allen (westlichen) Versionen von win XP und Win 2003 lauffaehig sein. Egal also, ob jemand z.B. eine (US-)englische oder eine deutsche Win Version verwendet.

Die gewaehlten Dateien sollen ein bestimmtes Alter erreicht haben, welches frei bestimmbar ist. Die zu pruefenden Verzeichnisse sollen frei waehlbar sein. Ebenso die Dateinamen und Dateitypen. Die Verarbeitung und Auswertung von Wildcards (aka Platzhaltern - also das Sternchen * und das Fragezeichen ?) ist deshalb angezeigt. Anwendungskomfort und Sicherheit gegen Fehlbedienung sollen auf keinen Fall aus dem Blick gelassen werden sondern unser wichtigstes Ziel sein.

Da es um eine kritische Aufgabe geht (das Loeschen von Dateien) ist eine ausgekluegelte Fehlerkontrolle unabdingbar und vor dem endgueltigen Ausfuehren des Auftrags sollte eine Ueberpruefung durch den Anwender moeglich sein.

Da vorher i.d.R. nicht bekannt ist, wieviele Dateien zu bearbeiten sind, es koennten 3, 30 oder 300 sein, ist das Anlegen, Anzeigen und Abarbeiten einer Auftragsliste zweckmaessig.


Es ist immer praktisch, auf vorhandene Funktionen des Betriebssystems zurueck zu greifen. Das erspart das Programmieren eigener Routinen. Das Anlegen einer Liste potentieller Loeschkandidaten kann darum z.B. der DIR-Befehl fuer uns uebernehmen. Wir passen seine Ausgabe dann einfach an unsere Erfordernisse an.

Zunaechst muessen wir aber mal ermitteln, in welchem Verzeichnis und nach welchen Dateinamen/-typen wir denn suchen sollen. Also schauen wir mal, was der Anwender denn dazu eingegeben hat und ordnen das passenden Variablen zur Weiterverarbeitung zu ...

Code:
 :split_filename
REMMuster "Lw:\Pfad\bsp. pfad\test abc.txt"

FOR %%a IN (pfad name ext target) DO SET %%a=
FOR /F %%a IN ("%~1") DO (
SET "pfad=%~dp1"
SET "name=%~n1"
SET "ext=%~x1"
SET "target=%~1"
)

IF EXIST "%pfad%%name%%ext%" GOTO job
GOTO no_file

REM /F- verwende die Befehlserweiterungen fuer 
REMDateinamen und Zeichenketten-Operationen
REM%~1- entfernt alle umschliessenden Anfuehrungszeichen von %1
REM%~f1 - gibt einen vollstaendigen Dateinamen fuer %1 aus
REM%~d1 - gibt den Laufwerkbuchstaben von %1 aus
REM%~p1 - gibt den Pfad von %1 aus
REM%~n1 - gibt den Dateinamen von %1 aus
REM%~x1 - gibt die Dateierweiterung von %1 aus
REM%~a1 - gibt die Dateiattribute von %1 aus
REM%~t1 - gibt Datum und Zeit von %1 aus
REM%~z1 - gibt die Dateigroesse von %1 aus
Vor jedem Verarbeitungsschritt sollten wir dafuer Sorge tragen, das Variable sich immer in einem definiertem Zustand befinden, um Fehler zu vermeiden und dadurch gelegentlich hoechst unangenehmen Ueberraschungen vorzubeugen (SET xy=).

Teilen wir nun die Eingabe auf und ordnen sie sinnvollen Variablen zu. Dazu bedienen wir uns der Bequemlichkeit halber einer Systemfunktion.

Gibt es wenigstens eine, auf die Eingabe passende Datei (IF EXIST), machen wir weiter (GOTO job). Wenn nicht, geben wir eine entsprechende Meldung aus, raeumen auf und beenden die Batchverarbeitung.

Code:
 :no_file
@ECHO OFF
ECHO.
ECHO--------------------------------------------------------
ECHOHinweis-folgende Datei existiert nicht:
ECHO.
ECHO"%pfad%%name%%ext%"
ECHO.
ECHOPfad- und Dateinamen, die Leerzeichen enthalten,
ECHOmuessen in Anfuehrungszeichen gesetzt werden.
ECHO--------------------------------------------------------
ECHO.
ECHO Das Programm wird jetzt geordnet beendet.
ECHO Bitte eine beliebige Taste druecken ... 
 PAUSE > NUL
GOTO clean-up
Existiert mindestens eine, auf die Eingabe passende Datei, sehen wir uns die Eingabe einmal naeher an.

Code:
 :job

IF []==[%ext%] IF NOT EXIST "%pfad%%name%\" SET ext=.
IF []==[%ext%] IF ""=="%name%" SET ext=.
IF []==[%ext%] SET pfad=%pfad%%name%\
IF []==[%ext%] SET name=.

IF "."=="%ext%" GOTO get_file_list
IF "."=="%name%" GOTO get_file_list
Handelt es sich bei der Eingabe um ein gueltiges Verzeichnis, ohne Wildcards im Pfadnamen, gibt Win den Pfad aus und setzt die Dateierweiterung als Punkt. In dem Fall koennen wir direkt mit dem Erstellen der Dateiliste beginnen (GOTO get_file_list).

Sind Wildcards im Pfadnamen der Eingabe, setzt Win den Pfad, der Name des ersten passenden Unterverzeichnisses wird als Dateiname zurueckgegeben und die Namenserweiterung bleibt leer.

In dem Fall koennen wir dann eine Liste moeglicher Unterverzeichnisse erstellen und abarbeiten oder wir verwenden zur weiteren Verarbeitung einfach das erste gefundene Verzeichnis, das auf die Anwendereingabe passt.

Ich habe mich fuer letzteres entschieden, in der Annahme, das zwar oft verschiedene Dateinamen/-typen gleichzeitig zur Verarbeitung gefordert werden, seltener aber mehrere verschiedene Verzeichnisse nebeneinander zugleich bearbeitet werden sollen. Ich habe mir also einen Verarbeitungsschritt erspart. :deal
Wer moechte, kann den Batch aber natuerlich um entsprechende Routinen ergaenzen ... vielleicht mache ich es irgendwann einmal auch selbst ... : )

Setzen wir also den Pfad auf das gefundene Verzeichnis, wenn es denn eines ist (IF NOT EXIST dann natuerlich nicht) und wenden wir uns dann gewuenschten Dateinamen/-typen zu.

Code:
 REMWildcards (*?) und Trennzeichen (:\) verarbeiten
SET cnt=

REMWildcards in der Eingabe ?
SET count=2
 ECHO %target% | FIND "*" > NUL
 IF ERRORLEVEL 1 SET /A count-=1
 ECHO %target% | FIND "?" > NUL
 IF ERRORLEVEL 1 SET /A count-=1
IF %count%==0 GOTO get_file_list

REMERRORLEVEL 1 = Zeichen(kette) nicht gefunden
REMERRORLEVEL 0 = Zeichen(kette) gefunden
Wir verwenden den FIND-Befehl, um festzustellen, ob ueberhaupt Wildcards (Platzhalter fuer Teile von Dateinamen oder Pfadangaben) eingegeben wurden. Wenn nein, koennen wir direkt mit der Erstellung der Dateiliste fortfahren (GOTO get_file_list).
Wenn doch, muessen wir die Eingabe zerlegen.

Code:
 REMDoppelpunkt in der Eingabe ?
 ECHO "%target%" | FIND ":" > NUL
IF ERRORLEVEL 1 GOTO Backslash
 CALL :finde_Trennzeichen :
SET target=%cnt%
SET cnt=
Wurde eine Laufwerksbezeichnung eingegeben ?

Code:
 :Backslash in der Eingabe ?
 ECHO "%target%" | FIND "\" > NUL
IF ERRORLEVEL 1 GOTO Wildcards
 CALL :finde_Trennzeichen \
SET target=%cnt%
SET cnt=
Wurde eine Pfadangabe gemacht ?

Wieder findet auch hier der FIND-Befehl Verwendung. Um die Angaben zwischen den gefundenen Trennzeichen zu erhalten, rufen wir eine Subroutine auf und teilen ihr beim Aufruf mit, nach welchem Trennzeichen gefiltert werden soll (CALL :finde_Trennzeichen x).

Code:
 :finde_Trennzeichen
FOR /F "TOKENS=1* DELIMS=%1" %%a IN ("%target%") DO (
IF []==[%%b] SET cnt=%%a
SET target=%%b
)
IF []==[%cnt%] GOTO finde_Trennzeichen
GOTO :EOF
REM :end_finde_Trennzeichen
Da wir noch nicht wissen, wieviele gueltige Trennzeichen in der Eingabe enthalten sind, arbeitet die Routine sie einfach rekursiv von links nach rechts ab, bis das letzte Segment gefunden ist. Dieses bleibt dann als Ergebnis zur Weiterverarbeitung in der Variablen stehen.
TOKENS gibt an, welche Elemente der aktuellen Kette wir haben moechten. In diesem Fall jeweils das erste Element (1) und alles (*) NACH dem Trennzeichen (zur Rekursion) in je einer eigenen Variablen.
DELIMS (Delimitations = Abgrenzungen) gibt an, bei welchen gefundenen Trennzeichen die Zeichenkette aufgespalten werden soll. Es wird in diesem Fall jeweils beim Aufruf der Subroutine im Parameter %1 uebergeben.

Code:
 :Wildcards im Dateinamen ?
SET count=2
 ECHO %target% | FIND "*" > NUL
 IF ERRORLEVEL 1 SET /A count-=1
 ECHO %target% | FIND "?" > NUL
 IF ERRORLEVEL 1 SET /A count-=1
IF %count%==0 GOTO get_file_list

SET name=%target%
SET ext=%cnt%
Nun haben wir also einen in der Eingabe enthalten Dateinamen gefunden. Enthaelt er Platzhalter? Dann werden diese in die Variable zur Dateisuche uebernommen.

Endlich koennen wir die Dateiliste erstellen. Dazu leiten wir die Ausgabe des DIR-Befehls in eine Datei. Es ist dabei immer guter Stil, dem Anwender so ungefaehr mitzuteilen, was gerade passieren soll, statt ihn vor dem leeren Bildschirm dumm 'rum sitzen zu lassen ...

Code:
 :get_file_list
REM Directory Liste erstellen
REMaufsteigend sortiert nach Datum

ECHO.
ECHOpruefe jetzt"%pfad%%name%%ext%". . . 
DIR /OD /4 /-P /N "%pfad%%name%%ext%" | FIND /V "<DIR>" | FIND ":" > %TEMP%.\$Dummy1.txt

REM/OD-nach Datum sortieren
REM/-P-wir koennen bei der Ausgabeumleitung keine Stopbefehle gebrauchen; ) 
REM/N -Ausgabe im "neuen" Format in der Reihenfolge Datum, Zeit, Groesse, Name
REM/4 -die Jahreszahl fuer den Datumsvergleich vierstellig ausgeben. (Wozu, werden wir gleich noch sehen.)

REMFIND /Vzeigt alle Zeilen an, die "Zeichenfolge" NICHT enthalten.
Auch hier findet erneut der FIND-Befehl Anwendung, um die relevanten Ergebniszeilen zu erhalten. Zuerst filtern wir die Zeilen mit den Verzeichniseintraegen heraus. Die brauchen wir hier nicht (/V).

Dann suchen wir die Angaben zu evtl. gefundenen Dateien, in dem wir nach dem Trennzeichen der Zeitangabe suchen (":"). Das ist im Gegensatz zum Datumstrennzeichen naemlich in allen westlichen Win Versionen gleich ... : )

Warum verwenden wir beim DIR-Befehl nicht gleich das Attribut /A-D ?
Ausgabe aller Eintraege, die nicht das Directory-Attribut tragen ?

Weil dann eine Fehlermeldung am Bildschirm ausgegeben wuerde, wenn das angefragte Verzeichnis keine Dateien enthaelt. Das liesse sich aber nicht abfangen und man koennte im Batchablauf nicht darauf reagieren, da die internen Kommandos den ERRORLEVEL nicht setzen/veraendern. Deshalb der kleine "Umweg" ueber den FIND-Filter ; )

Wir haben jetzt also eine Verzeichnisliste namens $Dummy1.txt stilgerecht im Verzeichnis fuer temporaere Dateien (uebernommen aus der Systemvariablen %TEMP%). Existiert kein TEMP-Verzeichnis (unwahrscheinlich) oder wurde die TEMP-Variable geloescht, wird die Liste im aktuell gueltigen Verzeichnis erstellt. Dafuer sorgt der kleine Punkt zwischen %TEMP% und dem Backslash. : D
Diese Liste muessen wir nun noch ein wenig bearbeiten und vor allem auswerten.

Wir benoetigen von den in Frage kommenden Dateien nur das Datum und den Namen ...

Code:
 :main

REMListe in Frage kommender Dateien erstellen

ECHO.> %TEMP%.\$Dummy2.txt
SET age=
SET target=
SET count=0
FOR /F "SKIP=3 TOKENS=1,3* DELIMS= " %%a IN (%TEMP%.\$Dummy1.txt) DO (
SET age=%%a
SET target=%%c
CALL :write_file_list
)

IF %count%==0 GOTO no_file
REMsry, aber keine Datei im Pfad gefunden ... :(
... das ist erste Element (%%a) der jeweiligen Zeile und der ganze Rest NACH dem dritten Element (%%c). Naemlich der Dateiname samt Namenserweiterung und eventuell enthaltener Leerzeichen (!) im Dateinamen.

Die ersten 3 Zeilen ueberspringen wir dabei (SKIP). Sie enthalten nur Angaben zur Festplatte und zum durchsuchten Pfad.

Ausserdem klaeren wir gleich die Frage: Wurde ueberhaupt eine Datei im abgefragten Verzeichnis gefunden ?

Code:
 :write_file_list
ECHO %age% %target%>> %TEMP%.\$Dummy2.txt
SET /A count+=1
GOTO :EOF
REM :end_write_file_list
Um nun das Dateialter zu pruefen muessen wir erst mal das Loeschdatum berechnen. Also das Datum, mit dem wir vergleichen wollen, ob die gefundene Datei alt genug ist, um sie loeschen zu wollen.

Zunaechst brauchen wir also das aktuelle Datum. Das steht in der Systemvariablen DATE.

Aber in welchem Format steht es dort? Schliesslich ist bei den Anwendern nicht nur die deutsche Version von Win im Einsatz ...

Code:
 REMDas Datum kann in Win in drei verschiedenen Formaten 
REMvorliegen, abhaengig von der lokalen Win Version.

REMForm-1 alsTT MM JJJJ - Tag Monat Jahr(z.B. deutsche und UK engl. Vers.)
REMForm-2 alsMM TT JJJJ - Monat Tag Jahr(z.B. US engl. Vers.)
REMForm-3 alsJJJJ MM TT - Jahr Monat Tag(z.B. ungarische Vers.)

REMAls Trennzeichen kommen Punkt, Bindestrich und Schraegstrich in Frage (.-/). 
REMSie sind in allen Win Versionen bei der Eingabe als Trennzeichen gueltig.
REM Beim Format dagegen muss bei Ein- und Ausgabe lokal unterschieden werden.
Also muessen wir erstmal herausfinden, in welchem Format es auf dem gegenwaertigem PC vorliegt. Sehen wir nach, was im Augenblick in der Systemvariablen DATE steht ...

Code:
 SET dform=0
FOR %%a IN (jahr monat tag) DO SET %%a=
REMaktuelles Datum
REM !!tag monat jahrsind nur Platzhalter fuer die Werte von %%a %%b und %%c !
REM Sie repraesentieren in diesem Abschnitt nicht zwingend TAG, MONAT und JAHR !!
FOR /F "TOKENS=1,2,3 DELIMS=.-/" %%a IN ("%DATE%") DO (
SET /A tag=%%a
SET /A monat=%%b
SET /A jahr=%%c
)
Wenn wir Glueck haben, ist nicht gerade Neujahr oder der erste April etc. sondern ein Tag zwischen dem 13. und dem Monatsende. Warum?

Code:
 IF %monat% GTR 12 SET dform=2
IF %tag% GTR 12 SET dform=1
IF %tag% GTR 31 SET dform=3
IF %dform% GTR 0 GOTO parameter
Ganz einfach. Der Wert fuer den Monat kann nur Werte von 1 bis 12 aufweisen. Ist der mittlere Teil der DATE-Variablen groesser 12 kann demzufolge nur Form 2 vorliegen - MM TT JJJJ.

Ist der linke Teil der Variablen groesser 12 handelt es sich um Form 1 - TT MM JJJJ oder Form 3 - JJJJ MM TT.
Ist dieser Teil also groesser 31, liegt in jedem Fall Form 3 vor.


Was aber, wenn der Tag im Bereich vom 1. bis zum 12. eines Monats liegt und Form 3 ausgeschlossen ist ?
Dann muessen wir die Moeglichkeiten austesten ...

Code:
 SET /A tag+=12
ECHO. | DATE %tag%-%monat%-%jahr%
Wieso +12 ? Einfach. An diesem Punkt des Programmablaufs ist Form 3 bereits ausgeschlossen. Es geht nur noch darum, zwischen Form 1 und Form 2 zu unterscheiden - also TTMM oder MMTT.

Fangen wir den Check am besten mit dem im deutschsprachigem Raum meistverbreitetem Format an und setzen die Position mit dem vermutetem Tag um den Wert 12 herauf. Denn an dieser Stelle des Programms liegt der Wert fuer den aktuellen Tag des Datums irgendwo zwischen 1 und 12 (jaja, ich weis - genau genommen zwischen 0 und 13).
Indem wir nun 12 hinzu addieren, erhoehen wir den Wert also mindestens auf die Zahl 13 und erreichen damit auf jeden Fall einen Wert groesser als der hoechstzulaessige Wert fuer Monat.

Wie schon erwaehnt, geben interne Kommandos leider keinen ERRORLEVEL zurueck. Deshalb muessen wir den Erfolg oder Misserfolg der Aktion durch nochmaliges Ueberpruefen des Wertes der DATE-Variable feststellen ...

Code:
 FOR /F "TOKENS=1 DELIMS=.-/" %%a IN ("%DATE%") DO (
SET /A tag=%%a
)
IF %tag% GTR 12 SET dform=1
Zur Ueberpruefung brauchen wir diesmal nur den linken/ersten Teil der Variablen (TOKENS=1). Hatten wir mit dem DATE-Befehl Erfolg, so wird der Tag jetzt groesser 12 angezeigt und wir haben die richtige Form ermittelt. TT MM JJJJ.

Natuerlich stimmt nun das Datum nicht mehr, da wir den Wert fuer den Tag erhoeht hatten. Das muessen wir korrigieren und wieder zuruecksetzen.

Gut, das wir den Wert fuer Tag um genau 12 erhoeht hatten, statt einfach eine beliebige Zahl zwischen 12 und 30/31 (28 ; ) Februar) zu setzen. So koennen wir den richtigen Wert fuer Tag ganz einfach wieder herstellen, indem wir 12 abziehen.

Selbst wenn dies Programm um Mitternacht herum laeuft und mittlerweile gerade ein neuer Tag begonnen hat, ist das Ergebnis dann immer noch das richtige ... : D

Code:
 IF %dform%==1 SET /A tag-=12
Hatten wir mit dem DATE-Befehl keinen Erfolg, so ist der Wert an der linken Position der DATE-Variablen unveraendert kleiner als 13. - Bleibt fuer das Format also nur noch Form 2 - MM TT JJJJ.
Ueberpruefen wir das, indem wir die mittlere Position um 12 erhoehen ...

Code:
 IF %dform%==0 SET /A monat+=12
ECHO. | DATE %tag%-%monat%-%jahr%
IF %dform%==1 GOTO parameter
Durch die IF Abfragen ist es egal, ob wir den linken Wert zuruecksetzen muessen oder zwecks abschliessender Pruefung den mittleren Wert erhoehen wollen. Der Effekt wird immer der richtige sein ... : )

nur abfragen muessen wir den (mittleren) Wert nochmal ... (TOKENS=2)

Code:
 FOR /F "TOKENS=2 DELIMS=.-/" %%a IN ("%DATE%") DO (
SET /A monat=%%a
)
IF %monat% GTR 12 SET dform=2
IF %dform%==2 SET /A monat-=12
ECHO. | DATE %tag%-%monat%-%jahr%
IF %dform%==2 GOTO parameter
Spaetestens jetzt muss das Format einfach bestaetigt sein. MM TT JJJJ.

Code:
 GOTO date_error
REMSchwerer Fehler! - Kann Systemdatum nicht ermitteln.
REMSollte bei Win Versionen mit westlichem Zeichensatz ausgeschlossen sein.
Wenn nicht, haben wir ein riesengrosses Problem ... :O

Code:
 :date_error
@ECHO OFF
ECHO.
ECHO--------------------------------------------------------
ECHOSchwerer Fehler! - Kann Systemdatum nicht ermitteln.
ECHO--------------------------------------------------------
ECHO.
ECHO Das Programm wird jetzt geordnet beendet.
ECHO Bitte eine beliebige Taste druecken ... 
 PAUSE > NUL
GOTO clean-up
Nachdem wir nun das Datumsformat kennen, koennen wir das

Code:
 REMLoeschdatum berechnen

FOR %%a IN (jahr monat tag cnt) DO SET %%a=
CALL :datum_%dform%
SET cnt=%days%
CALL :get_loesch_datum

SET datum=%jahr%%monat%%tag%
Nanu - fragen wir hier das aktuelle Datum nicht ein zweites Mal direkt nacheinander ab ? Haben wir das nicht eben schon getan ? - Nein. Im vorhergehenden Abschnitt waren TAG, MONAT und JAHR nur Platzhalter fuer die Werte von %%a %%b und %%c ! Das richtige Format kannten wir ja noch nicht. Erst jetzt ordnen wir die Variablen entsprechend dem ermitteltem Datumsformat richtig zu, indem wir die passende Subroutine aufrufen ... (CALL :datum_%dform%)

Code:
 REM :akt_Datum

:datum_1
FOR /F "TOKENS=1,2,3 DELIMS=.-/" %%a IN ("%DATE%") DO (
SET /A tag=%%a
SET /A monat=%%b
SET /A jahr=%%c
)
GOTO :EOF

:datum_2
FOR /F "TOKENS=1,2,3 DELIMS=.-/" %%a IN ("%DATE%") DO (
SET /A tag=%%b
SET /A monat=%%a
SET /A jahr=%%c
)
GOTO :EOF

:datum_3
FOR /F "TOKENS=1,2,3 DELIMS=.-/" %%a IN ("%DATE%") DO (
SET /A tag=%%c
SET /A monat=%%b
SET /A jahr=%%a
)
GOTO :EOF

REM :end_akt_Datum
Der Vergleichswert fuer das Loeschdatum ergibt sich aus dem aktuellen Datum und dem Wert fuer die Tage, die eine Datei mindestens alt sein soll, indem wir die beiden einfach von einander abziehen. Einfach ? Naja ...

Code:
 :get_loesch_datum
 IF %tag% LEQ %cnt% (
SET /A tag+=31
FOR %%a IN (5 7 10 12) DO (
IF %monat%==%%a SET /A tag-=1
)
IF %monat%==3 SET /A tag-=3
SET /A monat-=1
)
 IF %monat%==0 (
SET /A jahr-=1
SET monat=12
)
 IF %tag% GTR %cnt% (
SET /A tag-=%cnt%
SET cnt=0
)
IF NOT %cnt%==0 GOTO :get_loesch_datum

FOR %%a IN (1 2 3 4 5 6 7 8 9) DO (
IF %monat%==%%a SET monat=0%%a
IF %tag%==%%a SET tag=0%%a
)
GOTO :EOF

REMDer 29. Feb. in Schaltjahren findet keine Beruecksichtigung,
REMum die Berechnungen nicht unnoetig komplex zu gestalten.

REM :end_get_loesch_datum
Was geschieht hier ?

Zunaechst vergleichen wir mal, ob der Wert fuer %tag% kleiner oder gleich dem Wert ist, der der gewuenschten Zahl an Tagen entspricht, die fuer das Mindestalter der zu pruefenden Dateien vorgesehen ist.

Ist das der Fall, addieren wir die Anzahl der Tage der Vormonats zum Wert fuer %tag% hinzu. Vom Wert fuer %monat% ziehen wir natuerlich 1 ab.

Aber die Monate haben unterschiedlich viele Tage ? - Kein Problem. Addieren wir zunaechst auf jeden Fall mal 31. Sieben von zwoelf Monaten des Jahres haben 31 Tage. Mehr als die Haelfte decken wir damit also schon mal ab. :D

Dann ziehen wir 1 ab, wenn der Vormonat nur 30 Tage hat. Das kommt im Jahr genau nur viermal vor. Aber wieso steht da 5 7 10 und 12 (Mai Juli Oktober Dezember) ? Die haben doch 31 Tage ... Klar - als aktuell gesetzter Monat ... aber ihr jeweiliger Vormonat hat nur 30 Tage ... und DEN loesen wir ja auf ... : )

Dann fragen wir ab, ob der aktuell gesetzte Monat der Maerz ist. Ist das der Fall, ziehen wir fuer den Februar eben 3 Tage von den zuvor zugefuegten 31 ab. Den 29. Februar schenken wir uns und berechnen den Feber immer mit 28 Tagen.

Jetzt (!) ziehen wir vom Wert fuer %monat% 1 ab. Verrechnen wir dadurch zufaellig gerade den Januar und der Wert fuer %monat% faellt auf 0, muessen wir natuerlich vom Wert fuer %jahr% auch 1 abziehen und den Wert fuer %monat% dann auf 12 setzen.

Ist der Wert fuer %tag% jetzt groesser, als der Wert fuer die Anzahl Tage, die eine Datei aelter sein soll, so ziehen wir sie voneinander ab. Wenn nicht, wiederholen wir den Durchgang.

Nun sorgen wir noch dafuer, das die Werte fuer %tag% und %monat% eine fuehrende Null erhalten, falls sie kleiner sind als 10. - Warum ?

Nun - das Ergebnis der Subroutine wird nach dem Ruecksprung zum Wert fuer die Variable %datum% zusammengesetzt in der Form JJJJMMTT.

Das ergibt einen einmaligen und unverwechselbaren Vergleichswert fuer das Loeschdatum.
Ein mathematischer Vergleich in der Form JJJJMMTT kleiner/gleich JJJJMMTT wird IMMER das richtige Ergebnis liefern.
Beim mathematischem Vergleich zweier Zahlen z.B. nach dem Muster TTMMJJJJ kleiner/gleich TTMMJJJJ waere das nicht der Fall ... :D

Aus diesem Grund liessen wir uns vom DIR-Befehl die Jahreszahl auch vierstellig ausgeben. Damit bei einem Vergleich mit Dateien z.B. von 1999 dann auch das richtige Ergebnis zu Stande kommt ... 19990101 kleiner/gleich 20060201 und nicht etwa 990101 kleiner/gleich 060201 ... na ? gut aufgepasst ? ; )

Nun koennen wir das

Code:
 REMDateialter pruefen

ECHO.> %TEMP%.\$Dummy3.txt
FOR %%a IN (jahr monat tag target) DO SET %%a=
GOTO :alter_%dform%

:alter_1
FOR /F "TOKENS=1,2,3* DELIMS=.-/ " %%a IN (%TEMP%.\$Dummy2.txt) DO (
SET tag=%%a
SET monat=%%b
SET jahr=%%c
SET target=%%d
CALL :proof_age
)
GOTO count_hit_lines

:alter_2
FOR /F "TOKENS=1,2,3* DELIMS=.-/ " %%a IN (%TEMP%.\$Dummy2.txt) DO (
SET tag=%%b
SET monat=%%a
SET jahr=%%c
SET target=%%d
CALL :proof_age
)
GOTO count_hit_lines

:alter_3
FOR /F "TOKENS=1,2,3* DELIMS=.-/ " %%a IN (%TEMP%.\$Dummy2.txt) DO (
SET tag=%%c
SET monat=%%b
SET jahr=%%a
SET target=%%d
CALL :proof_age
)
REM GOTO count_hit_lines
Auch hier richten wir uns natuerlich wieder nach dem ermitteltem Datumsformat ... und hier kommt nun der eben schon besprochene Vergleich in Form JJJJMMTT LESS OR EQUAL JJJJMMTT zum Tragen ...

Code:
 :proof_age
IF %jahr%%monat%%tag% LEQ %datum% ECHO %tag%.%monat%.%jahr% %pfad%%target%>> %TEMP%.\$Dummy3.txt
GOTO :EOF
REM :end_proof_age
und auch der Pfadname sollte gleich mit hinzugefuegt werden, um Irrtuemer oder Verwechslungen auszuschliessen.

Warum nicht einfach nur auf KLEINER vergleichen ? Damit wir auf Wunsch auch Dateien loeschen koennen, wenn sie nur einen Tag alt sind, also das Datum von gestern tragen und der Vergleichswert %datum% ist ja zumindest das Datum vom Vortag ...

Sehen wir nun mal nach, auf wieviele Dateien das Kriterium Loeschalter zutrifft ...

Code:
 :count_hit_lines
SET count=1
FOR /F "EOL=- TOKENS=1 DELIMS=[]" %%a IN ('FIND /N " " "%TEMP%.\$Dummy3.txt"') DO (
SET /A count=%%a
)
SET /A count-=1

IF %count%==0 GOTO no_match
REMsry, aber keine Datei im Pfad ist alt genug ... : ) 

REMFIND /Nzeigt alle "Zeichenfolge" enthaltenden Zeilen mit ihren Zeilennummern an.

REM :end_get_file_list
Vom Ergebnis ziehen wir 1 ab. Immerhin haben wir ja in jedem Fall eine leere Datei mit dem ECHO-Befehl erstellt. Das erzeugt zumindest eine Leerzeile, auch wenn im Datumsvergleich keine zutreffende Datei ermittelt wurde.
Und diese Leerzeile wollen wir ja nun nicht unbedingt als Erfolg mit werten ... :D

Der Parameter /A zum Befehl SET bewirkt, dass das Argument arithmetisch (mathematisch, nummerisch) ausgewertet wird, bevor es der gewuenschten Variablen als Wert zugewiesen wird.

Keine passende Datei gefunden ? Dann geben wir eine entsprechende Meldung aus ...

Code:
 :no_match
@ECHO OFF
ECHO.
ECHO--------------------------------------------------------
ECHO Hinweis:
ECHO.
ECHOKeine der Dateien im Pfad ist alt genug.
ECHO--------------------------------------------------------
ECHO.
ECHO Bitte eine beliebige Taste druecken ... 
 PAUSE > NUL
GOTO done
doch was gefunden ? Dann sollten wir dem Anwender auch anzeigen, was wir gefunden haben ...

Code:
 REMLoeschliste ist fertig

FOR %%a IN (jahr monat tag cnt) DO SET %%a=
CALL :datum_%dform%
SET cnt=%days%
CALL :get_loesch_datum

ECHO.
ECHO--------------------------------------------------------
ECHO Ihnen wird gleich eine Liste mit%count%Datei(en) 
ECHO angezeigt.
ECHO.
ECHO Diese sind vom%tag%.%monat%.%jahr%oder aelter.
ECHO.
ECHO Bitte pruefen Sie die Liste sorgfaeltig und 
ECHOentscheiden Sie dann, ob Sie die aufgefuehrte(n) 
ECHO Datei(en) wirklich loeschen moechten.
ECHO--------------------------------------------------------
ECHO.
ECHO Zum Fortfahren bitte eine beliebige Taste druecken ... 
 PAUSE > NUL

TYPE "%TEMP%.\$Dummy3.txt" | MORE
dazu verwenden wir den TYPE-Befehl. Der kann die erstellte Liste fuer uns anzeigen. Fuer den Fall, das sie sehr umfangreich ist, sorgt der MORE-Befehl dafuer, das der Anwender auch alles mitbekommt ...

Nun sollten wir dem Anwender aber auch die Chance geben, die Liste nach der Sichtung zu bestaetigen oder ggf. zu verwerfen.

Code:
 :Abfrage
 SET cnt=
 ECHO.
 ECHO Abfrage:
 SET /P cnt=Diese Datei(en) loeschen ? [J/N]
FOR %%a IN (j J) DO IF [%%a]==[%cnt%] GOTO do_it
FOR %%a IN (n N) DO IF [%%a]==[%cnt%] GOTO end_Abfrage
 REM CLS
 ECHO.
 ECHO Sorry, ungueltige Eingabe:%cnt%
 ECHO.
 ECHO Zum Fortfahren bitte eine beliebige Taste druecken ... 
 PAUSE > NUL
GOTO Abfrage

:end_Abfrage

ECHO.
ECHO.
ECHO Ok, diese Dateien werden NICHT geloescht.
ECHO.
GOTO done
Antwortet der Anwender mit 'n' oder 'N' wird die Liste verworfen. Ein Loeschvorgang findet dann nicht statt.

Hat der Anwender die Liste bestaetigt, wuenscht das Loeschen der angezeigten Dateien und hat also mit 'j' oder 'J' geantwortet, tun wir den vorletzten Schritt ...

Code:
 :do_it

ECHO.
ECHO Dateien werden jetzt geloescht . . . 

ECHO @ECHO OFF> %TEMP%.\$Dummy4.txt
ECHO.>> %TEMP%.\$Dummy4.txt
SET target=
SET cnt=
SET count=0
IF NOT %mk%==2 SET cnt=/P
FOR /F "TOKENS=1* DELIMS= " %%a IN (%TEMP%.\$Dummy3.txt) DO (
SET target=%%b
CALL :write_kill_list
)
ECHO.>> %TEMP%.\$Dummy4.txt
ECHO ECHO.>> %TEMP%.\$Dummy4.txt
ECHO ECHO %count%Datei(en) geloescht.>> %TEMP%.\$Dummy4.txt
ECHO ECHO.>> %TEMP%.\$Dummy4.txt
Erst jetzt (!) erstellen (!) wir tatsaechlich, basierend auf der bestaetigten Loeschliste, eine Routine, die den eigentlichen Loeschvorgang vornimmt.

Der Inhalt der Variable %cnt% bestimmt, ob zusaetzlich VOR dem Loeschen JEDER einzelnen Datei eine systemeigene Sicherheitsabfrage erfolgen soll ...

Code:
 :write_kill_list
ECHO IF EXIST "%target%" DEL %cnt% "%target%">> %TEMP%.\$Dummy4.txt
SET /A count+=1
GOTO :EOF
REM :end_write_kill_list
Hinweis:
Wer dieses Batchprogramm erst einmal voellig gefahrlos testen moechte, ersetzt bitte in der fertigen Batch-Datei zunaechst mal das Befehlswort CALL aus dem naechsten Abschnitt in der Zeile SET cnt=CALL durch das Befehlswort TYPE ...
SET cnt=TYPE
So kann in aller Ruhe betrachtet werden, wie dies Batch-Programm arbeitet ...

Das Erzeugen von zunaechst einer txt-Datei (:write_kill_list), die erst unittelbar vor der Ausfuehrung in eine bat-Datei umbenannt wird (REN), die dann ausgefuehrt, den eigentlichen Loeschjob uebernimmt, ist sozusagen ein letztes doppeltes Sicherheitsnetz.

Bleibt, aus welchen ungluecklichen Umstaenden auch immer (Systemabsturz, Abbruch, Stromausfall, ...) eine txt-Datei im Temp-Verzeichnis zurueck, kann sie normal nicht viel Schaden anrichten. Ein bat-File koennte immer noch von einem DAU oder einfach aus Unkenntnis (Kinder, Ehegatten, Arbeitskollegen, ...) durch fehlerhaftes Anklicken versehentlich gestartet statt betrachtet werden und evtl. nachtraeglich noch unerwuenscht Schaden anrichten.

Code:
 ECHO.
SET cnt=CALL
IF EXIST %TEMP%.\$Dummy4.bat DEL %TEMP%.\$Dummy4.bat
IF EXIST %TEMP%.\$Dummy4.txt REN %TEMP%.\$Dummy4.txt $Dummy4.bat
IF EXIST %TEMP%.\$Dummy4.bat %cnt% %TEMP%.\$Dummy4.bat

GOTO done

REM :end_main
Nach dem Job sollte natuerlich auch eine Vollzugsmeldung erfolgen. Die erfolgt u.a. durch die abschliessende Zeile
... ECHO %count% Datei(en) geloescht. ...
im erzeugten bat-File (siehe Abschnitt :do_it).

Code:
 REM :end_job

:done

REM-----------------------

REM :statistics
ECHO.
ECHO Anfrage:%1
ECHO.
ECHOPfad:%pfad%
ECHOName:%name%
ECHO Ext:%ext%
ECHO.
ECHO Datum heute:%date%
ECHOMindestalter: %days%Tag(e)
ECHOVergleichswert:%datum%
ECHODatumsformat:%dform%
ECHO.
ECHO Counter:%count%
ECHOMarker:%mk%

REM-----------------------

 SHIFT
IF []==[%1] GOTO clean-up
GOTO parameter

REM :end_done
Die 'statistics' dienen der Information. Man kann sich hier nochmal vor Augen fuehren, was man denn da gerade eigentlich gemacht hat. : D

Der Befehl SHIFT befoerdert dann den aktuell gerade abgearbeiteten Parameter von seinem Platz. Gibt es weitere Angaben, wird der Job mit den naechsten Parametern wiederholt. Dem Batch-Programm koennen also mehrere abzuarbeitende Eingaben beim Aufruf uebergeben werden.
z.B.: older.bat *.bac briefe\*.ba? vorlagen\*.tmp *.tst Kopie*.doc
oder: older.bat "meine Gedichte\*.ba?" "\alte texte\Kopie (?) von *"

Bitte daran denken: Dateiangaben, die Leerzeichen enthalten, muessen in Anfuehrungszeichen gesetzt werden.

Nach dem Job (und natuerlich auch bei jedem vorzeitigem kontrolliertem Beenden des Programms) sollte immer auch aufgeraeumt werden ...

Code:
 :clean-up
@ECHO OFF
 FOR %%a IN (pfad name ext age jahr monat tag dform datum) DO SET %%a=
 FOR %%a IN (count target days cnt mk) DO SET %%a=
 FOR %%a IN (1 2 3 4) DO IF EXIST %TEMP%.\$Dummy%%a.txt DEL %TEMP%.\$Dummy%%a.txt
 FOR %%a IN (1 2 3 4) DO IF EXIST %TEMP%.\$Dummy%%a.bat DEL %TEMP%.\$Dummy%%a.bat

:ende
ECHO.
Wer das Programm erstmal ausprobieren will, kann vor die letzten beiden Zeilen ein REM setzen und sich nach einem Durchlauf ansehen, was en detail in den temporaeren Dateien zwischengespeichert ist und wie es jeweils weiterverarbeitet wurde ...

Das sollte es jetzt gewesen sein.

Aber ist das Programm schon fertig ?

Naja - Am Anfang eines guten Programms sollte immer stehen, was es macht und unter welchen Bedingungen es das tut. Also ...

Code:
 @ECHO OFF
REMolder.bat
REMDateien loeschen, die xx Tage alt und aelter sind
REMworks on win XP & 2K3
REM2006-02-01 
REMby Mial

REMverwendete Variable:
REM (pfad name ext age jahr monat tag dform datum)
REM (count target days cnt mk)
REMDATE ERRORLEVEL

CLS

IF []==[%1] GOTO Syntax Fehler
Die Befehlszeile @ECHO OFF
am Anfang einer Batchdatei bewirkt, das waehrend der Abarbeitung nur erwuenschte (sinnvolle) Ausgaben am Bildschirm erscheinen. Fehlt die Zeile oder ist sie auskommentiert (z.B. durch ein REM ), so wird jede abzuarbeitende Zeile der Datei auch am Bildschirm ausgegeben. Das ist aber allenfalls als Hilfsmittel zur Fehlersuche sinnvoll ...

Wir listen die verwendeten Variablen auf und sorgen fuer freien Blick auf die Programmmeldungen. (CLS - clear screen).

Und dann pruefen wir gleich mal, ob beim Programmaufruf ueberhaupt Parameter uebergeben wurden. Ist das nicht der Fall, geben wir eine Kurz-Anleitung zum Programmaufruf mit den moeglichen und wahlfreien Angaben aus ...

Code:
 :Syntax Fehler
@ECHO OFF
ECHO.
ECHO--------------------------------------------------------
ECHOSyntax Fehler - der korrekte Aufruf lautet:
ECHO.
ECHOolder[.bat] [/noq] [/d xx] [Lw:\Pfad\][Filename.Ext]
ECHO.
ECHOParameter:/noq-gibt an, das vor 
ECHOdem Loeschen der einzelnen Dateien 
ECHOKEINE Sicherheitsabfrage erfolgen soll.
ECHO.
ECHOParameter:/d xx oder /D xx
ECHOxxdefiniert die Anzahl Tage, die die zu
ECHOloeschende(n) Datei(en) alt sein soll(en).
ECHO.
ECHOErlaubt sind ganze Zahlen von 1 bis 11680.
ECHO.
ECHOHinweis:
ECHO--------
ECHOPfad- und Dateinamen, die Leerzeichen enthalten,
ECHOmuessen in Anfuehrungszeichen gesetzt werden.
ECHOWildcards (* ?) in Pfad- und / oder Dateinamen 
ECHOsind erlaubt und werden ebenfalls verarbeitet.
ECHO.
ECHO !Parameter bitte NICHT in Anfuehrungszeichen. 
ECHO--------------------------------------------------------
ECHO.
ECHO Das Programm wird jetzt geordnet beendet.
ECHO Bitte eine beliebige Taste druecken ... 
 PAUSE > NUL
IF [%mk%]==[] GOTO ende
GOTO clean-up
Hat der Anwender die Batchdatei mit den notwendigen Angaben gestartet, bereiten wir das Programm auf sein Wirken vor.

Code:
 :init

SET mk=1
FOR %%a IN (noq NOQ Noq noQ NOq nOQ NoQ nOq) DO (
IF [/%%a]==[%1] SET mk=2
)
IF %mk%==2 SHIFT
IF []==[%1] GOTO Syntax Fehler
Wuenscht der Anwender zusaetzlich VOR dem Loeschen JEDER einzelnen Datei eine systemeigene Sicherheitsabfrage oder wurde der Parameter /noq (no query) gesetzt, weil er es nicht wuenscht ?

Da es sich nur um drei Zeichen fuer eine i.d.R. vermutlich nicht gewuenschte Operation handelt, beruecksichtigen wir auch gleich mal evtl. Tipfehler bei der Eingabe, die in Zusammenhang mit der Shifttaste stehen ... : ( : )

Code:
 SET days=2
REMvorgegebenes Mindest-Alter der zu loeschenden Dateien, falls per 
REMParameteruebergabe keine abweichende Eingabe vorgenommen wird
die REMarks erklaeren es schon ...

und wenn angegeben, lesen wir dann aus, wie alt die zur nachfolgenden Eingabe passenden Dateien mindestens sein sollen, um geloescht zu werden.

Code:
 :parameter
IF []==[%2] GOTO split_filename

FOR %%a IN (d D) DO (
IF [/%%a]==[%1] SET days=%2
)

IF %days%==%2 SHIFT
IF %days%==%1 SHIFT
IF []==[%1] GOTO Syntax Fehler

REMevtl. vorhandene fuehrende Nullen entfernen
 ECHO %days% | FIND "0" > NUL
IF NOT ERRORLEVEL 1 (
FOR /F "TOKENS=* DELIMS=0" %%a IN ("%days%") DO (
SET days=%%a
)
)

SET /A days=%days%
IF ERRORLEVEL 9000 GOTO out_of_range

IF %days% LEQ 0 GOTO out_of_range
IF %days% GTR 11680 GOTO out_of_range
REMtech. max. abs(32767) - log. max. 365 Tg. x 32 Jahre = 11680 Tg.
Enthaelt ein Argument als Wert (versehentlich) eine Zahl mit fuehrenden Nullen (z.B. 011) so wird es bei einer Variablen-Zuweisung mit dem Parameter /A als Oktalwert interpretiert. Bei einem Tipfehler in der Eingabe fuehrt das natuerlich zu kuriosen und unerwuenschten Ergebnissen. Deshalb entfernen wir vorsichtshalber evtl. vorhandene fuehrende Nullen.

Ausserdem findet natuerlich auch eine Gueltigkeitspruefung des uebergebenen Wertes statt.

Code:
 :out_of_range
@ECHO OFF
ECHO.
ECHO--------------------------------------------------------
ECHOSyntax Fehler-Out of Range
ECHO.
ECHODer Wert fuer den Parameter ( /d xx oder /D xx )
ECHOliegt ausserhalb des gueltigen Bereichs.
ECHO.
ECHOParameter:/d xx oder /D xx
ECHOxxdefiniert die Anzahl Tage, die die zu
ECHOloeschende(n) Datei(en) alt sein soll(en).
ECHO.
ECHOErlaubt sind GANZE Zahlen von 1 bis 11680.
ECHO--------------------------------------------------------
ECHO.
ECHO Das Programm wird jetzt geordnet beendet.
ECHO Bitte eine beliebige Taste druecken ... 
 PAUSE > NUL
GOTO clean-up
Da das Label :parameter auch als Wieder-Einsprung-Punkt nach einem Durchlauf gedacht ist, kann bei Angabe mehrerer Dateitypen oder Verzeichnisnamen hintereinander, jeweils fuer jede Angabe wahlweise ein eigenes Mindestalter vorgegeben werden.

Bsp.: older.bat M*.txt /d 30 *.bac /d 20 "Kopie (?) von *.doc" d:\texte\*.bak ...

Wird nicht erneut ein Mindestalter angegeben, so wird die jeweils letzte Angabe verwendet.

Wird gar kein Mindestalter angegeben, so wird die Vorgabe aus dem vorstehenden Abschnitt uebernommen.


Damit sollten jetzt alle notwendigen Module erstellt und erlaeutert sein.


Die Anordnung der Module in der fertigen Batch-Datei im Anhang ist fuer die Abarbeitung durch einen Kommando-Interpreter angepasst. Die Reihenfolge entspricht somit nicht dem seriellen Programmablauf sondern dient der Sprungoptimierung. Evtl. zeitrelevante Routinen befinden sich deshalb am Anfang der Datei.


In einer Compiler-Version wuerde z.B. die Modulanordnung wiederum deutlich anders aussehen. Oder die im Batch mehrfach verwendete Befehlszeile
ECHO %target% | FIND "%irgendwas%" > NUL
Sie wuerde dann z.B. in einer Subroutine landen. : D


Dennoch wurde eine gewisse Strukturierung der Uebersichtlichkeit wegen beibehalten. REM Zeilen dienen der Erlaeuterung, Leerzeilen der Gliederung. Die Erfahrung zeigt, das nach einer gewissen Zeit sonst nur erschwert nachvollziehbar ist, was in den Programmzeilen durchgefuehrt wird. ; )

Natuerlich waere eine weitere Optimierung des Codes moeglich. Sie ginge aber vermutlich zu Lasten der Struktur und macht nur fuer wirklich alte Computer evtl. Sinn.

Meine Absicht war es, ein uebersichtliches, zweckgerichtetes, komfortables und moeglichst 'sicheres' Batchprogramm zu schreiben. Gerade auch beim sensiblen Vorgang des Datei loeschens ... Lieber eine Pruefroutine zu viel, als ein ungewollter Datenverlust. Deshalb z.B. auch die staendige Ueberpruefung und die streng definierte Zuweisung an variable Platzhalter.


Jegliche Aenderung, Erweiterung oder 'Optimierung' an diesem Programmcode ist selbstredend erlaubt, geschieht aber natuerlich ausdruecklich auf eigenes Risiko. : )

cu
:cool
m,-
 

Anhänge

T

Tobias28

Mitglied seit
21.09.2005
Beiträge
853
:danke Solche Beiträge machen Winboard noch wertvoller... :repect
 
M

ModellbahnerTT

Mitglied seit
20.04.2005
Beiträge
3.778
Alter
39
:danke @Mial Da hast du dir aber ganz schön viel Arbeit gemacht. :repect

ModellbahnerTT
 
M

Mial

Threadstarter
Mitglied seit
14.07.2004
Beiträge
2.132
Hi Tobias28, ModellbahnerTT und mastcont

danke fuer die Blumen ... :aah


ca. 10 Stunden fuer den Text, jeweils ebensoviel fuer die Programmierung und die Codierung, dazu Korrekturlesen (die verflixten Tipfehler :-) ) und natuerlich ausgiebiges Testen und Pruefen der Routinen auf Denk- und Logikfehler (z.B. die verzwickte Syntax bei der Stringverarbeitung des Kommando-Interpreters), Ergaenzungen, Aenderungen oder Verbesserungen ... :D

----------

1. Nachtrag zum Artikel.

Warum verwende ich unterschiedliche Zeichen bei Vergleichsabfragen ?

Bsp.
Code:
 IF []==[%ext%] ...

IF "."=="%name%" ...
Das ist kein Versehen. Bei Vergleichsabfragen darf ein Parameter niemals voellig leer sein. Es kaeme, abhaengig vom Text der Befehlszeile, zu einer Fehlermeldung und bestenfalls zum unkontrollierten Abbruch der Programmausfuehrung. Eine Variable sollte deshalb bei Vergleichsoperationen zur Sicherheit immer mit zusaetzlichen Zeichen versehen sein.

Um zu kennzeichnen, das auf einen "leeren" Wert hin abgefragt wird, die Variable aber keineswegs leer sein muss, um gueltig zu sein, verwende ich die eckigen Klammern. Sie symbolisieren sofort auf einen Blick: leer. Nichts enthalten.

Wird mit Zeichenketten verglichen, die Leerzeichen enthalten koennen, aber eben keineswegs leer sind, muessen wir jedoch zwingend Anfuehrungszeichen verwenden. Der Kommando-Interpreter wuerde sonst naemlich lediglich auf die unmittelbar neben den Gleichheitszeichen stehenden Zeichen hin vergleichen und den ersten Ausdruck in der abzugleichenden Zeichenkette, der nach einem Leerzeichen folgt, als Befehl zu interpretieren versuchen ! Das wuerde (nicht nur) bei der Analyse von Pfad- und Dateinamen zu unvorhersehbaren und natuerlich voellig falschen Ergebnissen fuehren.

Dieses "Feature" existierte schon zu DOS-Zeiten und wurde auch in XP nicht veraendert ... :hehe

Beim Vergleich von Zeichenketten duerfen andere Markierungen als die Anfuehrungszeichen also nur verwendet werden, wenn genau bekannt ist, welche Werte die Variable enthalten wird - bzw. wenn sicher gestellt ist, das sich keine Leerzeichen in der zu pruefenden Zeichenkette befinden koennen.

cu
:cool
m,-
 
Cyron

Cyron

SPONSOREN
Mitglied seit
25.12.2004
Beiträge
3.280
Alter
30
Standort
far beyond /dev/null
Super, danke Mial.

Falls ich mal n Script schreibe weis ich wo ich die Infos dazu finde :-)

Finde den Topic so wichtig das ich ihn gepinnt hab.
Vielleicht laesst sich daraus ja noch n Wiki Artikel erstellen?

PS: Merkt ihr auch alle den Unterschied? Bin mit DSL unterwechs, nur die englische Tastatur nervt noch n bisschen ... aber von CD gestartet ohne Swap brauchts mit GUI nur 17,5 MB im RAM. :cool



Greetz Cyron
 
H

hal 9000

Gast
sind so alle programme von mial?

klasse :danke

@cyron

was merkt man denn? äh wobei?
 
(cs)Fishbone

(cs)Fishbone

Mitglied seit
11.11.2005
Beiträge
191
Alter
31
Standort
Halle/Saale
Ich sag nur eins ..... du hast Langeweile!!!!!!!


FIsh
 
T

Tobias28

Mitglied seit
21.09.2005
Beiträge
853
ZITAT((cs)Fishbone @ 01.02.2006, 16:05) Quoted post
Ich sag nur eins ..... du hast Langeweile!!!!!!!
[/b]
Zumindest nutzt er seine Zeit für extrem PRODUKTIVE Beiträge (im Gegensatz zu dir)...
 
frankbier

frankbier

Mitglied seit
20.10.2005
Beiträge
7.402
Standort
WinBoard



ps: hast dich in letzter Zeit auch rar gemacht jetzt weiß ich warum. :D
 
Fraenk0901

Fraenk0901

Mitglied seit
28.04.2005
Beiträge
598
Alter
64
Feine Sache @Mial!! :danke
Habe das gleich mal gesichert. Vieleicht kann @BrandyJr das mit in den Tutorials aufnehmen, natürlich mit deinem Einverständnis!

PS: Hast wohl während deiner Abwesenheit viele neue Kräfte getankt. :pfeifen
 
M

Mial

Threadstarter
Mitglied seit
14.07.2004
Beiträge
2.132
Hi

danke fuer die Zustimmung, die mein Batch-Artikel bisher gefunden hat. :danke

Natuerlich darf der Beitrag ohne Einschraenkungen von jedem, der es moechte, weiterverwertet werden. (Solange dabei niemand behauptet, er sei auf seinem Beet gewachsen :hehe ). Ich freue mich, wenn der Artikel jemandem nuetzlich ist. Dazu ist er ja gedacht.

Ich koennte mir auch vorstellen, dass er fuer ein Tutorial oder einen Wiki-Eintrag noch ergaenzt oder erweitert werden koennte. Fuer Batchprogrammierung gibt es ja jede Menge Tips und Kniffe. Ich wollte da nur mal einen Anfang machen und einen kleinen Beitrag dazu leisten.

----------

2. Nachtrag zum Artikel.

Warum bei der Berechnung des Loeschdatums nicht einfacher ...

Code:
 :get_loesch_datum
IF %tag% LEQ %cnt% (
FOR %%a IN (2 4 6 8 9 11 1) DO (
IF %monat%==%%a SET /A tag+=31
)
FOR %%a IN (5 7 10 12) DO (
IF %monat%==%%a SET /A tag+=30
)
IF %monat%==3 SET /A tag+=28
SET /A monat-=1
)
statt

Code:
 :get_loesch_datum
IF %tag% LEQ %cnt% (
SET /A tag+=31
FOR %%a IN (5 7 10 12) DO (
IF %monat%==%%a SET /A tag-=1
)
IF %monat%==3 SET /A tag-=3
SET /A monat-=1
)
Auch das hat einen Grund. - Auf den ersten Blick sieht das erste Bsp. vielleicht praktischer und uebersichtlicher aus, aber es waere deutlich ineffektiver, als der tatsaechlich verwendete Code aus dem zweiten Bsp. - Weil das in der ersten Form bei jedem Durchlauf zusaetzlich sieben (!) Arbeitsschritte bedeuten wuerde. Naemlich, fuer die moeglichen sieben Monate mit 31 Tagen in der FOR-Schleife jeweils eine IF-Abfrage durchzufuehren, bevor der SET-Befehl angewendet werden kann.

Statt dessen setzen wir den Wert fuer %tag% gleich um 31 herauf und ziehen dann in der folgenden ohnehin zu durchlaufenden Schleife in einem der 4 moeglichen Faelle wenn noetig eben einfach 1 von %tag% wieder ab.


Aber der PC hat doch genug Power. Der laeuft mit 2 GHz. - Das mag schon sein. Aber konsequent angewendet und uebertragen auf grosse Projekte (Programme) bedeutet diese Sorgfalt in den Ueberlegungen und Planungen, das man wirklich kompakte, effektive, schnelle und dennoch funktionelle und durchschaubare Programme schreiben kann ... :D

cu
:cool
m,-
 
M

Mial

Threadstarter
Mitglied seit
14.07.2004
Beiträge
2.132
Cyron wrote schrieb:
Super, danke Mial.
Finde den Topic so wichtig das ich ihn gepinnt hab.
Vielleicht laesst sich daraus ja noch n Wiki Artikel erstellen?
Hi Cyron

ich danke dir, fuer die Aufmerksamkeit. :sing

Cyron wrote schrieb:

Merkt ihr auch alle den Unterschied? Bin mit DSL unterwechs, nur die englische Tastatur nervt noch n bisschen ... aber von CD gestartet ohne Swap brauchts mit GUI nur 17,5 MB im RAM. :cool
aber englische Tastatur ? Anderes Betriebs-System am Ausprobieren ? Mit nur ~17 MB mit GUI muss es ja was ganz "kleines" (oder "altes") sein ...

und das du mit DSL unterwegs bist ? das kann ich hier an meinem Ende aber wohl nur schwerlich bemerken ... wie sollte das gehen ? :nixweis

cu
:cool
m,-
 
oele3110

oele3110

Mitglied seit
17.08.2004
Beiträge
1.152
Alter
30
Standort
Falkensee
Das ist echt Klasse Mial

:danke :danke :danke

Eine schöne Sache!!!

MFG Oele


P.S.: Mit DSL ist ein Betriebssystem gemeint, nicht der Internet-Anschluss :D

EDIT: Fast vergessen: :repect @ Mial!!!

EDIT2: Hinweis zu DSL:
ZITAT[17:42:15] Cyron: kennste dsl?
[17:42:24] Oele: jo
[17:42:32] Oele: internet anbindung?
[17:42:42] Cyron: rofl, nö
[17:42:46] Cyron: damn small linux
[17:42:56] Oele: aha
[17:43:23] Cyron: belegt nur 17,5 mb ram, nach dem livecd start :deal
[17:43:46] Cyron: und auf der cd nur 50 mb, macht dann selbst auf einem 100MHz keine prozie auslastung, wenn der idle is
[17:43:50] Cyron: einfach geil .... [/b]
 
M

Mial

Threadstarter
Mitglied seit
14.07.2004
Beiträge
2.132
Hi oele3110


ach klar :kopfklatsch Damn' Small Linux :hehe danke fuer die Denkhilfe ...

manchmal haeng ich eben auch am "falschen Anschluß" :D


cu
:cool
m,-
 
oele3110

oele3110

Mitglied seit
17.08.2004
Beiträge
1.152
Alter
30
Standort
Falkensee
Ich kannte das vorher gar nicht, aber die Namesgebung ist lustig, da sie zu großer Verwirrung beitragen kann :deal

MFG Oele
 
M

Mial

Threadstarter
Mitglied seit
14.07.2004
Beiträge
2.132
Hi oele3110

ja - ist ein Debian Derivat - sehr klein, sehr stabil. Kommt einem aber nicht oft unter die Augen ...

Hab's hier auch irgendwo "rumliegen" ... da ich aber "normal" unter den div. Win Versionen (oder DOS) arbeite und meist auch mehr tue, als nur surfen (irgendein Job laeuft eigentlich immer im Hintergrund) deswegen verwende ich es nicht. Und man denkt da darum normal eben auch nicht dran, wenn dann einer von DSL redet ... :D

cu
:cool
m,-
 
oele3110

oele3110

Mitglied seit
17.08.2004
Beiträge
1.152
Alter
30
Standort
Falkensee
Ich habe es mir mal gerade runtergeladen und werde es mal testen.

MFG Oele
 
Uese

Uese

WB Wiki - Team
Mitglied seit
24.10.2002
Beiträge
2.235
Alter
72
Standort
CH-8610 Uster
ZITAT((cs)Fishbone @ 01.02.2006, 16:05) Quoted post Ich sag nur eins ..... du hast Langeweile!!!!!!!


FIsh [/b]
@ cs Fishbone

Diese Bemerkung hättest Du Dir schenken können!! :no Ich finde sie nicht ganz fein und reichlich deplatziert. :angry:

Uebelege mal: Viele (inkl. meiner Wenigkeit) haben schon viel sinnlosere Beiträge hier gepostet, ohne dass uns jemand der Langeweile bezichtigte.
Mial hat eine Menge Arbeit in seinen Beitrag gesteckt und nur, weil Du vielleicht mit dem Thema Batch-Programme nichts anfangen kannst, heisst das noch lange nicht, dass es andere nicht interessiert. Auch ich verstehe (trotz Mials Beitrag) eigentlich nichts davon, aber ich würde mich hüten, seine Arbeit deswegen mit "Langeweile haben" abzutun.
Konsequenterweise müsstest Du demnach jeden Beitrag, der hier veröffentlicht wird, dem Umstand zuschreiben, dass der Verfasser Langeweile hatte. So geht es doch nicht..

Grüsse
 
Thema:

Wie man/frau ein (Batch-)Programm schreibt

Sucheingaben

hexadezimal fehler datum batch

Wie man/frau ein (Batch-)Programm schreibt - Ähnliche Themen

  • Frau nach trennung aus dem Microsoft Konto Familie löschen

    Frau nach trennung aus dem Microsoft Konto Familie löschen: Hallo , wollte meine Ex-Frau Löschen doch da kommt ein Hinweis mit meinen Kindern, das ich Sie nicht mehr ändern kann wie bekomme ich meine...
  • Hotmail Konto meiner Frau vom gemeinsam genutzten PC nicht erreichbar, da Outlook immer sofort in me

    Hotmail Konto meiner Frau vom gemeinsam genutzten PC nicht erreichbar, da Outlook immer sofort in me: Wir haben beide eine Hotmail.com Adresse, die wir bisher gut vom gemeinsamen PC erreichen konnten. Wie wir es neuerdings auch versuchen, Outlook...
  • Ok - eigentlich soll man/frau hier nur Fragen stellen...

    Ok - eigentlich soll man/frau hier nur Fragen stellen...: Aber ich möchte - da es vielleicht auch anderen Insidern/Insiderinnen helfen könnte, mal kurz darlegen, wie es nach gefühlten 1 millionen...
  • Meine Frau kann in unseren gemeinsamen Kalender keine Termine eintragen

    Meine Frau kann in unseren gemeinsamen Kalender keine Termine eintragen: Ab diesem Thread teilen. Ich habe exakt das gleiche Problem, und zwar seit einem Monat: Meine Frau kann in unseren gemeinsamen Kalender keine...
  • GTA 5: "Gewalt gegen Frauen" lässt australische Handelskette den Verkauf stoppen

    GTA 5: "Gewalt gegen Frauen" lässt australische Handelskette den Verkauf stoppen: Der Rockstar-Spielehit Grand Theft Auto 5 ist von zwei australischen Handelsketten aus dem Programm genommen worden, da eine Online-Pedition die...
  • Similar threads

    Oben