Batch-Kurs für Einsteiger in 20 Lektionen von Horst Schaefferfür MS-DOS bis V7.0, Stand: Juni 98Besuchen Sie auch Horst Schaeffer's Software Pages mit vielen nützlich Batch Tools & Utilities für MS-DOS |
Der Kurs ist 1994 erstmals im FIDO Echo BATCH.GER erschienen, und wurde mehrmals überarbeitet, zuletzt unter Berücksichtigung von WIN95 (MS-DOS 7.x).
Inhaltsübersicht:
|
============= BATCH-Kurs für Einsteiger - Einleitung =============== Ausgabe 98/06 (c) 1994..98 Horst Schaeffer -------------------------------------------------------------------- Dieser Batch-Kurs soll die Grundkenntnisse zur Batch-Programmierung unter MS-DOS vermitteln. Der Kurs ist 1994 erstmals im FIDO Echo BATCH.GER erschienen, und wurde mehrmals überarbeitet, zuletzt unter Beruecksichtigung von WIN95 (MS-DOS 7.x). Historische DOS-Versionen vor 3.3 werden nicht mehr berücksichtigt, da sie wohl kaum noch benutzt werden. Grundlagen der Befehlseingabe unter MS-DOS (Command Prompt) und Kenntnisse der Eigenschaften von Dateinamen und Pfaden werden hier vorausgesetzt. Die Standardbefehle von MS-DOS sollten auch bekannt sein. Erläuterungen können bei Bedarf auf der Befehlsebene mit <Befehl> /? abgerufen werden. Der vorliegende Text ist ein DOS-Text, also mit Umlauten gem. DOS- Zeichensatz. Fragen, Hinweise, Anregungen bitte im FidoNet Echo BAT.GER oder per Mail: Horst Schaeffer, FIDO 2:2480/13.75 horst@confusion.rmc.de =========== BAT Abläufe ============================ Lektion #1 ==== Die Grundidee der Batch-Abläufe ("Stapelverarbeitung") ist die automatische Abarbeitung von Programmen und Befehlen, z.B. um nach dem Einschalten des Computers eine Reihe von residenten Programme zu installieren (AUTOEXEC.BAT). DOS bietet dazu die Möglichkeit, Befehle aus einer ASCII-Datei zeilenweise abzuarbeiten, so als würden sie nacheinander auf der Befehlsebene eingegeben. Eine solche Datei muß den Namenszusatz "BAT" haben, und ist damit, neben COM- und EXE-Dateien, eine weitere Variante der "ausführbaren" Dateien, die als Befehl auf der DOS-Ebene gestartet werden können. Damit ein BAT-Ablauf mehr ist, als nur eine einfache Folge von Programm-Aufrufen, gibt es besondere Anweisungen und Eigenschaften, die einfache Funktionen einer Programmiersprache bieten: * Befehlsparameter (%1..) * Bildschirm-Ausgaben (ECHO) * Halt (PAUSE) * Variable (SET, Umgebungsvariable) * Bedingte Ausführung (IF.. GOTO, Labels) * Schleifen (FOR..) * CALL weiterer BAT-Abläufe * Ein-/Ausgabe-Umleitungen Die BAT-Sprache ist allerdings von Microsoft äußerst spärlich ausgestattet worden. Bildschirmdialoge, etwa für Eingaben oder Auswahl durch den Benutzer sind nur in Ansätzen vorhanden. Aus diesem Grunde sind schon viele nützliche Erweiterungen der BAT- Sprache entwickelt worden, die aber meist nur isolierte Befehle bieten, ohne die BAT-Sprache selbst (d.h. die Programm-Logik) zu verbessern. Das Problem liegt darin, daß der BAT-Prozessor von DOS ein fester Bestandteil von COMMAND.COM ist, also kein separates Programm, das man so einfach durch ein besseres ersetzen könnte. Das oft zitierte 4DOS ersetzt COMMAND.COM komplett und kann daher mit einem eigenen, erheblich erweiterten BAT-Prozessor aufwarten. Soviel zu Batch-Erweiterungen. Hier in diesem Einsteiger-Kurs soll es nur um das reine MS-DOS gehen, und zwar ab Version 3.3. Ältere DOS-Versionen sind im Funktionsumfang der BAT-Verarbeitung noch stärker eingeschränkt und spielen heute keine Rolle mehr. Bevor in den nächsten Lektionen die einzelnen BAT-Befehle behandelt werden, hier noch einige Basis-Informationen: BAT-Datei, ASCII ---------------- Um BAT-Dateien zu schreiben, braucht man einen ASCII-Editor, z.B. den von MS mitgelieferten EDIT. Auch ein WIN Editor kann verwendet werden, allerdings werden z.B. bei NOTEPAD deutsche Umlaute nicht nach DOS-Standard gespeichert. In einer BAT-Datei dürfen beliebige Zeichen verwendet werden, mit Ausnahme des EOF-Codes (Ctrl-Z, ASCII 26), der generell als Ende einer ASCII-Datei interpretiert wird. Jede Zeile wird durch CR+LF (ASCII 13,10) abgeschlossen. Einige Sonderzeichen haben in BAT-Dateien eine besondere Funktion. Die Wichtigsten: das Prozentzeichen ist für Variable, die Größer- und Kleiner-Zeichen sowie das "|" sind für Ein-/Ausgabeumleitungen reserviert. Näheres bei den jeweiligen Befehlen. Leerzeilen werden ignoriert (wie ein ENTER auf der Befehlsebene), können also zur besseren Lesbarkeit eingebaut werden. Die Länge der Batchzeilen ist bis MS-DOS 6.x auf 127 Zeichen begrenzt, und zwar nachdem eventuelle Variable eingesetzt wurden (s. Lektion über Variable). Ab Version 7 (WIN95) darf die Batchzeile 255 Zeichen lang sein, intern (nach Einsetzen der Variablen) sogar 1023 Zeichen (s.a. COMMAND Optionen /U und /L). Abarbeitung durch DOS --------------------- Zur Kontrolle des Ablaufs legt COMMAND.COM beim Start im Arbeits- speicher einen BAT-Steuerblock an, der am Ende wieder entfernt wird (64 Bytes oder auch etwas mehr). In diesem Steuerblock wird unter anderem ein Zeiger auf die nächste auszuführende Zeile der BAT-Datei verwaltet. Für jede einzelne Befehlszeile des Batch-Ablaufs wird von DOS die BAT-Datei geöffnet, gelesen und geschlossen. Grundsätzlich kann also eine BAT-Datei auch verändert werden, während sie läuft, was man allerdings mit Vorsicht genießen sollte. Auf jeden Fall sollte man vermeiden, in einem Batch-Ablauf den Editor aufzurufen, um eben diese BAT-Datei zu ändern. Das bringt die Abarbeitung mit hoher Wahrscheinlichlkeit durcheinander! Fehler in BAT-Ablauf, Abbruch ----------------------------- Bei ungültigen Befehlen oder Syntax-Fehlern gibt DOS eine Meldung aus und setzt die Verarbeitung (wenn möglich) mit der nächsten Zeile fort. Bei schweren Fehlern wird der BAT-Ablauf abgebrochen. Da DOS nicht die Zeilen-Nummer des Fehlers angibt, muß man notfalls die einzelnen Befehlszeilen auf dem Bildschirm ausgeben lassen, um den Ablauf zu verfolgen (s. Lektion ECHO). Ab MS-DOS 6.x ist auch ein Einzelschritt-Modus verfügbar. Dazu wird die Batchdatei mit folgendem Aufruf gestartet (s. COMMAND Optionen): COMMAND /Y/C batch.BAT COMMAND zeigt dann jede einzelne Zeile und fragt, ob sie ausgeführt werden soll oder nicht. Eine laufende BAT-Datei läßt sich normalerweise mit Control-C oder Control-BREAK (Strg-Unterbr.) abbrechen. DOS erwartet dann noch eine Bestätigung: Stapelverarbeitung abbrechen? (J/N) Ob und wie sich ein gerade ausgeführtes PROGRAMM abbrechen läßt, ist natürlich eine andere Frage. =========== ECHO, @ ================================ Lektion #2 ==== Der ECHO-Befehl hat zwei verschiedene (!) Funktionen: 1. Echo-Status einstellen/ausgeben 2. Textzeile ausgeben Echo-Status einstellen/ausgeben ------------------------------- ECHO [ON|OFF] Der Echo-Status legt fest, ob die folgenden Anweisungszeilen der BAT-Datei jeweils vor der Ausführung auf dem Bildschirm ausgegeben werden (ON) oder nicht (OFF). Ausgaben erfolgen immer mit dem DOS- Prompt, genau so wie es auf der Befehlsebene aussehen würde. Normalerweise wird das ECHO in BAT-Dateien gleich am Anfang OFF geschaltet und höchstens streckenweise ON geschaltet, damit man sieht, welche Befehle gerade ausgeführt werden. Auch zum Testen ist ECHO ON manchmal ganz nützlich, um Fehler zu lokalisieren. Nach dem Wort ECHO kann optional ein "=" eingefügt werden. Leerzeichen sind erlaubt. Beispiel: ECHO=off ECHO = on Dies ist allerdings nicht (?) dokumentiert, und man sollte vielleicht darauf verzichten, wenn man kompatibel bleiben will. Der ECHO-Befehl ohne Angaben veranlaßt DOS, den derzeitigen Status nach folgendem Muster auszugeben: ECHO ist eingeschaltet Das braucht man so gut wie nie, und wenn diese Meldung auf dem Bildschirm erscheint, dann meistens unbeabsichtigt (s.u.). Text ausgeben ------------- Bei allen ECHO-Befehlen, die nicht den obigen Bedingungen entsprechen, wird der Rest der Zeile auf dem Bildschirm ausgegeben (genauer gesagt: zum Standard-Ausgabe-Gerät). Beispiel: ECHO Dies ist eine ECHO-Zeile Durch Leerzeichen läßt sich der Text einrücken: ECHO Dieser Text ist eingerückt Das erste Leerzeichen nach ECHO gilt jedoch als Trennzeichen und gehört nicht zum Text. Alternativ kann ein Punkt verwendet werden, z.B: ECHO.Fertig ECHO.OFF (OFF ist hier Text!) Auf diese Weise läßt sich auch eine leere Zeile, also ein extra Zeilenvorschub, produzieren (ECHO allein bewirkt was anderes! s. ECHO-Status). Beispiel: ECHO. Der Punkt muß ohne Leerzeichen anschließen, sonst ist er Text! Bei MS-DOS können anstelle des Punktes auch andere Sonderzeichen verwendet werden, sofern sie nicht in Befehlen bzw. Dateinamen gültig sind (,:;+/). Probiert's mal auf der Befehlszeile! Ganz wichtig: ECHO Texte dürfen nicht die Zeichen "<", ">" oder "|" enthalten, da diese für Umleitungen/Pipes reserviert sind. Wer mal nicht dran denkt, wird sich über äußerst merkwürdige Fehlermeldungen oder unerwartet auftauchende Dateien wundern. ECHO-Ausgaben dürfen auch Steuerzeichen (ASCII 1..31) enthalten, sofern sie nicht die Abarbeitung sabotieren (wie z.B. CR oder EOF) Wenn der Editor es erlaubt, kann man z.B. jederzeit ein Control-G (BELL, ASCII 7) einbauen. Ausprobieren! Klammeraffe (at-sign) --------------------- Während das ECHO ON ist, kann es bei Bedarf für einzelne Zeilen abgeschaltet werden, indem ein Klammeraffe an den Anfang der Zeile gesetzt wird. Spezielles Beispiel: @ECHO OFF Ohne den Klammeraffen würde der Befehl selbst noch ge-echot, bevor er wirksam wird (!) Dieser Befehl steht üblicherweise am Anfang jeder Batch-Datei. ECHO auf der Befehlsebene ------------------------- Der ECHO-Befehl kann grundsätzlich auch auf der Befehlsebene verwendet werden, was aber nur in Sonderfällen sinnvoll ist. Achtung: ECHO OFF bewirkt, daß kein DOS-Prompt mehr erscheint!! Mit anderen Worten: wenn der Prompt mal auf unerklärliche Weise verschwunden ist, einfach ECHO ON versuchen. Weitere Informationen --------------------- Interresant wird der ECHO-Befehl erst mit Umleitungen/Pipes. Außerdem können mit Hilfe der ANSI-Sequenzen Farben und Cursor- Steuerungen (u.a.) ins Spiel gebracht werden. Mehr dazu später. =========== ECHO Umleitung ========================= Lektion #3 ==== Das Thema "Umleitungen" soll eigentlich erst später behandelt werden, aber die ECHO-Umleitung wird schon mal vorweg genommen, weil sie recht unproblematisch ist. Ein ECHO-Text kann sehr einfach mit einem ">"-Zeichen (Pfeil nach rechts) in eine Datei oder an ein anderes Gerät - wie LPT1, also an den Drucker - umgeleitet werden. Beispiel: ECHO irgendwas> TEST.DAT ECHO irgendwas> LPT1 Genau wie auf dem Bildschirm, wird auch in diesen Fällen der Text mit einem Zeilenvorschub (CR,LF) ausgegeben. Eine leere Zeile (also nur ein Zeilenvorschub) kann so ausgegeben werden: ECHO.> TEST.DAT Die angegebene Datei wird neu angelegt, d.h. wenn diese Datei bereits vorhanden war, wird sie ohne Warnung überschrieben!! Es ist aber auch möglich, eine Zeile an eine vorhandene Datei anzufügen. Dazu werden einfach zwei Pfeile (">>") verwendet: ECHO eine Zeile > TEST.DAT ECHO noch eine Zeile >> TEST.DAT Übrigens: eventuelle Leerzeichen vor dem Pfeil werden mit in die Datei geschrieben! Die ECHO-Umleitungen lassen sich gut auf der Befehlsebene testen. =========== PAUSE ================================== Lektion #4 ==== Mit der PAUSE-Anweisung wird der BAT-Ablauf angehalten. DOS gibt dazu standardmäßig diese (oder eine ähnliche) Aufforderung aus: Weiter mit beliebiger Taste . . . Ein Abbruch ist an dieser Stelle, wie üblich, mit Control-C oder Control-BREAK (Strg-Unterbr.) möglich. Soll mehr als nur die Standard-Meldung erscheinen, können vorher geeignete ECHO-Anweisungen gemacht, werden, z.B.: ECHO Bitte Diskette wechseln! Pause Beim PAUSE-Befehl werden weitere Angaben in der selben Zeile ignoriert. Allerdings werden eventuelle Umleitungszeichen <|> von DOS konsequent abgearbeitet, was selten Sinn macht - bis auf diesen Fall: PAUSE > NUL Damit wird die Ausgabe der Standardaufforderung ins Nichts umgeleitet, falls man etwas anderes per ECHO formuliert hat. Hinweis: Bis DOS Version 5.0 war es nicht möglich, die gedrückte Taste anschließend abzufragen. Auch eine automatische Fortsetzung nach einer gewissen Zeit war nicht vorgesehen. Ab DOS 6.0 wird dafür das Hilfsprogramm CHOICE mitgeliefert (s. Lektion CHOICE). =========== REM - Bemerkungen ====================== Lektion #5 ==== REM dient zum Schreiben von Bemerkungszeilen, also von Kommentaren, die nicht ausgegeben werden. Bitte auch hier keine Umleitungszeichen <|> verwenden, sofern nicht wirklich beabsichtigt. Alternativ können Bemerkungszeilen mit dem für Sprungmarken vorgesehenen Doppelpunkt geschrieben werden, am besten mit Doppel- Doppelpunkt (weitere Informationen dazu s. Lektion LABEL). Beispiel: :: Das ist eine Bemerkung Der Vorteil dieser Version besteht vor allem darin, daß dabei bedenkenlos Umleitungszeichen verwendet werden, z.B.: :: Syntax: MOP <Quelldatei> <Zieldatei> [/M|/X] Empfehlung daher: Vergeßt REM für Bemerkungen. Die Doppelpunkt- Lösung ist sowieso schneller, auch wenn das heute praktisch keine Rolle mehr spielt... Nur für einen speziellen Fall ist REM wirklich nützlich: zum Anlegen einer leeren Datei per Umleitung, z.B.: REM > XXX.DAT REM mach mal eine leere > XXX.DAT Da REM nichts ausgibt, wird auch nichts in die Datei umgeleitet. Aber angelegt wird sie. =========== Befehlsparameter %1.. ================== Lektion #6 ==== In BAT-Abläufen werden oft variable Angaben gebraucht, die erst mit dem jeweiligen Aufruf festgelegt werden sollen. Dazu werden in der BAT-Datei "Platzhalter" eingebaut. Beim Start einer BAT-Datei werden dann die aktuellen Werte einfach zusätzlich in der Befehlszeile angegeben (Befehlsparameter). Platzhalter bestehen aus einem Prozentzeichen mit der laufenden Nummer des Befehlsparameters, also %1.....%9 (nur *eine* Ziffer möglich). Ein Beispiel (Datei EDR.BAT): attrib -R %1 EDIT %1 attrib +R %1 Aufruf: EDR ANY.TXT Hier wird vor dem Aufruf des Editors (EDIT) der Schreibschutz der angegebenen Datei entfernt und anschließend wieder eingeschaltet. DOS ersetzt die Platzhalter jeweils bevor eine Zeile interpretiert wird durch den entsprechenden Befehlsparamter. Auf diese Weise kann praktisch alles in einem BAT-Ablauf variabel gemacht werden, selbst Befehle und Programm-Aufrufe. Trennzeichen, Sonderzeichen --------------------------- Zur Trennung von Befehlsparametern können auch Komma oder Semikolon verwendet werden. Sie werden praktisch durch Leerzeichen ersetzt. (Auch das Gleich-Zeichen "=" wird auf die selbe Weise behandelt.) Leere Parameter können auf diese Weise NICHT übergeben werden. Beispiel: XXX.BAT eins,,,vier ergibt: %1=eins %2=vier Auch die Übergabe eines Parameters, in dem Leerzeichen enthalten sein sollen, ist bis einschließlich MS-DOS 6.x nicht möglich, denn Anführungszeichen werden wie ganz normale Zeichen behandelt. Beispiel (bis MS-DOS 6.xx): AAA.BAT "das Wort" ergibt: %1="das %2=Wort" Ab MS-DOS 7.0 werden (bedingt durch die langen Dateinamen) die Anführungszeichen interpretiert. Sie werden aber nicht entfernt. Beispiel (ab MS-DOS 7): AAA.BAT "Eigene Dateien" ergibt: %1="Eigene Dateien" Zum Ausprobieren empfiehlt es sich, eine TEST.BAT zu schreiben, die einfach 9 ECHO-Befehle enthält: @echo off ECHO.%1 ECHO.%2 (etc.) Dann kann diese BAT-Datei mit allen möglichen Kombinationen getestet werden. (Der Punkt nach ECHO sorgt dafür, daß bei leeren Parametern nicht die Meldung kommt "ECHO ist ausgeschaltet".) Parameter %0 ------------ Mit %0 kann man im BAT-Ablauf den Namen der BAT-Datei ansprechen, genauer gesagt, den Befehl, so wie er beim Aufruf angegeben wurde. Nur für spezielle Tricks zu gebrauchen. SHIFT-Befehl ------------ Kaum genutzt, aber der Vollständigkeit halber: SHIFT verschiebt die Parameter-Liste nach links, d.h. %0 fällt raus, der bisherige %1 wird zu %0 %2 wird zu %1 und so weiter Damit kann auch der zehnte Parameter erreicht werden (jetzt %9). SHIFT kann bei Bedarf wiederholt werden. Weitere Themen -------------- Variable Befehlsparameter können erst richtig eingesetzt werden, wenn man abfragen und verzweigen kann. Dazu gibt's Bedingungen (IF..), GOTO und Labels. =========== GOTO Label ============================= Lektion #7 ==== Ein GOTO geht zu einer anderen Stelle im BAT-Ablauf. Dazu muß die gewünschte Stelle markiert werden, und zwar mit einer Sprungmarke ("Label"). Eine Sprungmarke ist irgend ein Wort mit einem Doppelpunkt davor. Beispiel: :WEITER Mit dem Befehl GOTO WEITER irgendwo in der BAT-Datei würde also der Ablauf an dieser Stelle fortgesetzt. Ein GOTO wird natürlich erst interessant, wenn er bedingt eingesetzt werden kann, z.B.: IF not exist C:\COMMAND.COM goto FEHLER Aber bevor wir auf die IF-Konstruktionen eingehen, zunächst mal ein nützliches GOTO-Beispiel ganz ohne IF. Beispiel: GO.BAT ---------------- Angenommen es gibt Programme in verschiedenen Verzeichnissen, die jederzeit zu starten sein sollen, ohne daß man deswegen alle diese Verzeichnisse im PATH angeben will (der ist ja eh' schon lang genug). Man braucht also eine BAT-Datei, die jeweils den Verzeichniswechsel (CD) und dann den Aufruf ausführt. Für jedes Programm eine eigene BAT-Datei zu schreiben ist kein Kunststück. Aber wie kann man verschiedene Aufrufe in *einer* BAT-Datei steuern? Ganz einfach. Nennen wir die BAT-Datei: GO.BAT Sie enthält zunächst die Befehle: @echo off GOTO %1 Der Ablauf springt also direkt zu der Marke, die zum GO-Befehl angegeben wird. Als Marken dienen die Programmnamen oder irgend- welche Abkürzungen, die man sich leicht merken kann. Für jedes Programm wird nun eine kleine Aufruf-Routine geschrieben, z.B.: :TERM (Marke = Befehlszusatz) CD \MODEM\FD (Verzeichnis-Wechsel) FD /T (Programm-Aufruf) GOTO ENDE (BAT-Datei beenden) Natürlich können auch weitere Befehle (z.B. das Laden residenter Programme) in diese kleine Routine aufgenommen werden. Ganz am Ende der BAT-Datei sollte die Marke :ENDE nicht fehlen. Empfehlenswert auch ein anschließendes CD \ Damit lassen sich nun alle möglichen Programme nach diesem Muster aufrufen: GO TERM Falls allerdings kein Ziel oder ein falsches angegeben wird, meldet DOS "Sprungmarke nicht gefunden" und bricht ab. Das ist aber kein Problem. Eine aufwendige Prüfung auf gültige Befehle würde am Ende auch nichts anderes machen... Jetzt noch einige wichtige Hinweise für den Umgang mit Labels. Gültige Labels --------------- Eine Sprungmarke darf beliebig lang sein, aber DOS ignoriert alles, was über 8 Stellen hinausgeht! Falls mehrere Marken vorkommen, die (in den ersten 8 Stellen) gleich sind, wird immer nur die erste in der Datei gefunden. Groß-/Kleinschreibung ist egal. Auch z.B. "goto weiter" findet die Marke ":WEITER". Umlaute sollten allerdings vermieden werden, weil dabei die Umwandlung nur in eine Richtung funktioniert (Bug). Wenn Sonderzeichen verwendet werden, bitte nur solche, die auch in Dateinamen gültig sind. Andere Sonderzeichen sind Trennzeichen. Vorsicht: Ein "?" ist z.B. gültig, aber ein "*" ist absolut unbrauchbar. Am besten: keine dubiosen Sonderzeichen verwenden! Nach dem Leerzeichen oder Trennzeichen wird der Rest der Zeile ignoriert. Dies kann zur Kommentierung genutzt werden. Ersatz für REM --------------- Labels können hervorragend für Bemerkungszeilen mißbraucht werden, zumal dabei ausnahmsweise auch die Umleitungszeichen <|> bedenkenlos verwendet werden dürfen. Damit man gleich sieht, daß es sich nicht um eine echte Sprungmarke handelt, hat sich der doppelte Doppelpunkt eingebürgert, z.B.: :: Syntax: MOP <Quelldatei> <Zieldatei> [/M|/X] Sprungziel des GOTO-Befehls --------------------------- Auch im GOTO-Befehl darf der angegebenen Marke ein Doppelpunkt vorangestellt werden (Geschmacksache). Beispiel: GOTO :WEITER =========== Bedingungen, IF EXIST ================== Lektion #8 ==== Bedingungen werden durch IF-Ausdrücke formuliert. DOS bietet drei Varianten: IF [not] exist <Datei-Ausdruck> IF [not] errorlevel <n> IF [not] <Wort1>==<Wort2> Nach einer solchen Bedingung kann jede beliebige BAT-Anweisung stehen, z.B. ein GOTO, ein DOS-Befehl oder ein Programm-Aufruf. Die Anweisung wird nur ausgeführt, wenn die Bedingung WAHR ist. Das optionale NOT bedarf wohl keiner weiteren Erklärung. Da IF EXIST am einfachsten zu handhaben ist, soll zunächst mal mit diesem Ausdruck begonnen werden. Beispiele: IF exist TEST.BAK del TEST.BAK IF NOT exist TEST.DAT goto WEITER IF EXIST liefert WAHR, wenn die betreffende Datei existiert. Dabei können auch die Jokerzeichen "?" und "*" verwendet werden, und natürlich sind Laufwerk- und Pfadangaben erlaubt. IF EXIST C:\TEMP\*.* (irgendeine Datei in C:\TEMP ?) Unter DOS 7 sind Anführungszeichen erlaubt, unter WIN95 natürlich auch lange Dateinamen: IF EXIST "\Eigene Dateien\Word\bla bla.doc" ... Ungültige Datei-Angaben ------------------------ Bei Ungültigen Datei-Angaben oder Pfaden gilt die Datei als NICHT vorhanden. Es gibt also keine Fehlermeldung. Allerdings gibt's bei Laufwerken mit nicht eingelegtem Datenträger die übliche Meldung: Nicht bereit beim Lesen von Laufwerk ... Verzeichnis Vorhanden? ---------------------- Das Vorhandensein eines Verzeichnisses kann leider nicht direkt festgestellt werden, da DOS nur nach Dateinamen sucht. Man könnte zwar prüfen, ob Dateien im gewünschten Verzeichnis sind, aber damit wird ein evtl. leeres Verzeichnis nicht ermittelt. Es gibt jedoch eine einfache Abhilfe: man sucht nach NUL. NUL ist ein spezielles Gerät, das zwar nicht vorhanden, aber überall definiert ist. IF EXIST C:\TEMP\NUL Dieser Ausdruck ist nur dann WAHR, wenn der Pfad C:\TEMP gültig ist, egal ob Dateien vorhanden sind oder nicht. UND-Verknüpfung ---------------- Nach einer Bedingung können weitere Bedingungen in der selben Zeile folgen. Das entspricht einer UND-Verknüpfung. Beispiel: IF exist TEST.BAK if not EXIST TEST.NEU ren TEST.BAK TEST.NEU (und..) (dann..) Variabler Datei-Ausdruck ------------------------ Mit IF exist können auch variable Angaben überprüft werden: IF NOT exist %1 ECHO %1 ist nicht vorhanden --------------- Allerdings sollte man sichergehen, daß der angegebene Befehls- parameter nicht leer ist, denn dann bekäme COMMAND folgende Zeile zu lesen: IF NOT exist ECHO ist nicht vorhanden ------------------ Da eine Datei namens ECHO vermutlich nicht existiert, führt DOS den Befehl "ist" aus, sofern ein solches Programm vorhanden ist. Andernfalls Fehler: "Befehl oder Dateiname nicht gefunden". Dieses Problem besteht bei allen IF-Ausdrücken mit Variablen, weil COMMAND den variablen Wert bereits VOR der Interpretation der Zeile einsetzt. Bei leeren Variablen kommt so die gesamte Syntax des Befehls durcheinander. Häufigste Fehlermeldung daher: "Syntaxfehler". Nicht vorhandene (leere) Variable bzw. Befehlsparameter lassen sich mit der Vergleichsbedingung feststellen (nächste Lektion). =========== IF Wort1==Wort2 ======================== Lektion #9 ==== Wenn zwei Wörter verglichen werden sollen, so macht dies natürlich nur Sinn, wenn mindestens eines davon eine Variable ist, also ein Befehlsparameter oder eine "Umgebungsvariable". Hier soll es zunächst nur um Befehlsparameter gehen. (Bei Umgebungsvariablen gibt es zusätzliche Komplikationen, weil sie z.B. Leerzeichen und Sonderzeichen enthalten können.) Beispiel: IF %1==A: GOTO WEITER Achtung: DOS besteht auf dem doppelten "=". Sonst Syntax-Fehler! Leerzeichen vor und hinter den Gleich-Zeichen sind erlaubt. Groß-/Kleinschreibung wird unterschieden. Wenn also im obigen Beispiel ein kleines "a:" als Befehlsparameter angegeben wurde, ist die Bedingung NICHT wahr. Da hilft nur eines: beide Möglichkeiten abfragen. Leere Parameter --------------- Bei der IF EXIST Abfrage wurde schon gezeigt, daß leere Befehls- parameter die Syntax durcheinander bringen können. Beispiel: IF %1 == A: GOTO WEITER ergibt (wenn %1 leer): IF == A: GOTO WEITER Resultat: "Syntax-Fehler". Die Lösung des Problems: Man erweitert beide Seiten der Gleichung einfach um das selbe Zeichen. Beispiel: IF %1x == A:x GOTO WEITER ergibt (wenn %1 leer): IF x == A:x GOTO WEITER Zu diesem Zweck kann man beliebige Buchstaben verwenden, auch Sonderzeichen, ausgenommen Trennzeichen wie Komma, Semikolon, da diese ebenso wie Leerzeichen ignoriert werden. Eine gute Wahl sind z.B. Klammern oder Anführungszeichen (sie haben im BATCH nicht die sonst übliche Bedeutung und werden wie Buchstaben behandelt). Beispiel: IF "%1" == "A:" GOTO WEITER ergibt (wenn %1 leer): IF "" == "A:" GOTO WEITER Jetzt ist auch klar, wie man leere Parameter abfragt: Beispiel: IF [%1] == [] ECHO Bitte Laufwerk angeben! oder: IF "%1" == "" ECHO Bitte Laufwerk angeben! Fazit: Bei IF-Abfragen immer die hier beschriebenen Verfahren anwenden, sofern auch nur die geringste Möglichkeit besteht, daß Variable bzw. Befehlsparameter leer sein könnten. Anmerkung: In der Praxis ist alles halb so wild, weil oft Variable abgefragt werden, die man selbst vorher gesetzt hat. Damit kann man auch selbst dafür sorgen, daß die Variable nicht leer ist, und die Schreibweise (groß/klein) ist natürlich auch bekannt. Hinweis zu MS-DOS 7: Zwar dürfen Parameter in Anführungszeichen (lange Dateinamen) auch Leerzeichen enthalten, aber der IF.. Vergleich nimmt darauf leider keine Rücksicht. Näheres beim Thema Variable. =========== IF ERRORLEVEL n ======================== Lektion #10 === Jedes Programm gibt einen Return-Code ("Beendigungscode") an das aufrufende Programm zurück, normalerweise also an COMMAND.COM. Dieser Return-Code ist ein Byte und kann daher die Werte 0...255 haben. Um diesen Return-Code zu interpretieren, muß man natürlich wissen, welche Werte für welchen Fall von dem betreffenden Programm vorgesehen sind. In den meisten Fällen wird der Code benutzt, um mitzuteilen, ob ein Fehler aufgetreten ist: Null bedeutet "Programm ordnungsgemäß beendet", jeder andere Wert signalisiert einen Fehler. Wenn es "leichte" und "schwere" Fehler gibt, kann das Programm verschiedene Codes verwenden: je höher um so schwerwiegender der Fehler. Auf dieser Basis wurde die IF ERRORLEVEL... Abfrage im Batch konzipiert: IF ERRORLEVEL n bedeutet: IF Return-Code >= n (größer oder gleich n) So kann mit einer einzigen Abfrage (IF ERRORLEVEL 1) festgestellt werden, ob überhaupt ein Fehler aufgetreten ist, ohne daß alle anderen (möglicherweise gelieferten) Codes abgefragt werden müssen. Bei allen ERRORLEVEL-Abfragen muß man sich also der "größer/gleich" Logik bewußt sein. Wenn auf verschiedene Return-Codes reagiert werden soll, ist eine Abfrage in absteigender Folge erforderlich. Beispiel: Ein Programm kann die Return-Codes 0,1,3 und 9 zurück- geben. Dann lautet die Abfrage: IF errorlevel 9 goto Label-9 IF errorlevel 3 goto Label-3 IF errorlevel 1 goto Label-1 :: hier bleibt nur noch errorlevel 0 Übrigens: Die Abfrage "IF [not] ERRORLEVEL 0 ... " ist absolut witzlos, denn größer oder gleich Null ist der Return-Code IMMER. Um nur den Return-Code 0 abzufragen verwendet man logischerweise: IF NOT errorlevel 1 goto ... Soll nur ein ganz bestimmter Code abgefangen werden, z.B. 100, dann geht das so: IF errorlevel 100 IF NOT errorlevel 101 goto .... Noch ein Hinweis: Der Return-Code kann nur in dieser IF ERRORLEVEL Konstruktion angesprochen werden. Eine *direkte* Verwendung des Wertes (z.B. als Variable) ist nicht so ohne weiteres möglich. Andere Verwendung des Return-Codes ---------------------------------- Ein Programm kann natürlich den Return-Code auch für andere Zwecke als nur für Fehler verwenden. Z.B. kann ein Mailer mit bestimmten Codes mitteilen, was gerade anliegt. Auf jeden Fall muß vereinbart sein, welche Codes für welchen Zweck verwendet werden. Dafür gibt es keinerlei allgemeine Regeln. DOS-Befehle ----------- DOS-Befehle, also in COMMAND.COM integrierte Befehle ohne eigene Programmdatei, geben überhaupt keinen Return-Code zurück, auch nicht Null. Der zuvor produzierte Return-Code bleibt erhalten! Das hat den Vorteil, daß Befehle wie ECHO den letzten Return-Code nicht verändern, aber leider auch den Nachteil, daß man auf diese Weise nicht feststellen kann, ob z.B. ein COPY oder DEL erfolgreich war. Sonstige DOS-Dienstprogramme ---------------------------- Der FIND-Befehl gibt den erwarteten Errorlevel zurück: 0=gefunden, 1=nicht gefunden - allerdings erst seit MS-DOS Version 6.xx. Wer ähnliches z.B. von FC (Dateivergleich) erwartet, sieht sich leider getäuscht. Grundsätzlich sollte man sich also genau informieren, welche Return- Codes geliefert werden, wenn Errorlevel-Abfragen benutzt werden. Entsprechende Informationen sind teils in alten DOS-Handbüchern, teils auch in der HELP-Funktion (ab MS-DOS 6.xx), meist aber gar nicht zu finden. Notfalls also selbst testen. Hinweise dazu in späteren Lektionen. =========== CALL oder nicht CALL =================== Lektion #11 === In einem BAT-Ablauf lassen sich nicht nur .COM und .EXE Programme aufrufen, sondern auch andere .BAT Abläufe. Verwendet man nun den Namen einer BAT-Datei als Befehl, dann sollte man meinen, daß DOS - wie bei Ausführung eines Programmes - anschließend in der aufrufenden BATCH weitermacht. Das aber geht nur mit dem CALL-Befehl - sonst wird der (erste) BAT-Ablauf NICHT fortgesetzt! Dazu muß man verstehen, daß es in den ersten DOS-Versionen (vor DOS 3.3) gar keine Verschachtelung von BAT-Abläufen gab. Die Beendigung eines Batch-Ablaufs bei einem weiteren Aufruf war also zwangsläufig. Als DOS dann weiterentwickelt wurde, hat man halt den CALL erfunden. Also: XXX.BAT setzt den Ablauf in XXX.BAT fort, OHNE zur aufrufenden Batch zurückzukehren CALL XXX.BAT kehrt nach Ausführung von XXX.BAT zurück. Befehlsparameter können in jedem Falle übergeben werden, auch weitergegeben werden, z.B.: CALL update.bat %1 A: Nach Ausführung einer BATCH mit CALL sind selbstverständlich die Befehlsparameter des ersten Ablaufs wieder verfügbar, denn DOS führt für jede BAT-Ebene einen eigenen Steuerblock im Arbeitsspeicher, wo u.a. auch die jeweiligen Befehlsparameter abgelegt sind. Sollen von der aufgerufenen Batch irgendwelche Werte zurückgegeben werden, so sind dafür Umgebungsvariable zu verwenden (s. spätere Lektion). Der zuletzt von einem Programm erzeugte Return-Code kann aber noch nach der Rückkehr in die aufrufende Batch per ERRORLEVEL abgefragt werden. (Ein BAT-Ablauf selbst produziert keinen Return- Code/Errorlevel.) Rekursion --------- Grundsätzlich kann auch die selbe BATCH-Datei per CALL (rekursiv) aufgerufen werden, entweder direkt oder auf Umwegen über weitere CALLs, - aber dann sollte man schon was davon verstehen, sonst pflastert DOS den Arbeitsspeicher mit Steuerblöcken voll, von anderen möglichen Overflows ganz zu schweigen. Manchmal geschieht so etwas unbeabsichtigt. Übersichtliche CALL- Strukturen sind daher immer eine gute Investition. Rekursionen können auch auftreten, wenn aus einem Programm heraus (z.B. Mailer) eine weitere DOS-Shell mit Batch-Ablauf gestartet wird. Ohne saubere Trennung der einzelnen BAT-Ebenen kommt es hier leicht zu Überraschungseffekten... QUIT ---- Ein spezieller BAT-Aufruf ohne CALL hat sich als recht nützlich zum Beenden eines BATCH-Ablaufs erwiesen: Es wird einfach eine leere BAT-Datei, z.B. mit dem Namen QUIT.BAT, gerufen. Dies geht normalerweise schneller als ein GOTO ans Ende der laufenden BAT- Datei (was daran liegt, daß DOS keine sonderlich effiziente Batchverarbeitung hat). Beispiel: IF errorlevel 3 QUIT Anstelle der leeren QUIT.BAT kann auch eine einzeilige BAT-Datei mit folgendem Inhalt verwendet werden: %1 %2 %3 %4 %5 %6 %7 %8 %9 Damit wird aus allen Angaben (bis zu 9), die nach QUIT folgen, eine Befehlszeile produziert und ausgeführt. Oft läßt sich auf diese Weise eine extra GOTO-Konstruktion einsparen. Benutzungsbeispiele: IF ... QUIT cls IF ... QUIT echo Datei %1 ist nicht vorhanden - Abgebrochen! IF ... QUIT del *.TMP Abbruch bei GOTO-Fehler ----------------------- An dieser Stelle noch ein Hinweis auf eine besondere Tücke von DOS: Sollte bei einem GOTO das Sprungziel nicht gefunden werden, beendet DOS nicht nur die laufende BATCH mit einer Fehlermeldung, sondern sämtliche per CALL entstandene Verschachtelungsebenen! =========== FOR (Schleifen) ======================== Lektion #12 === Die FOR-Konstruktion ermöglicht die mehrfache Ausführung eines Befehls mit einem variablen Argument. Die Argumente werden nacheinander aus einer Liste entnommen. Beispiel: FOR %%a IN (X Y Z) DO echo %%a ------- -------- Liste Befehl Das hat die gleiche Wirkung wie: echo X echo Y echo Z Die Schlüsselwörter "IN" und "DO" sind vorgeschrieben. Die Argument-Liste muß immer in Klammern gesetzt werden. Und jetzt zu diesem "%%a": Erstens: Es kann jeder beliebige Buchstabe verwendet werden, nur keine Ziffer (für Befehlsparameter reserviert). Daß überhaupt verschiedene Buchstaben möglich sind, macht eigentlich keinen Sinn, denn diese Variable ist nur innerhalb der FOR-Zeile gültig, und ein mehrfaches FOR (Schachtelung) ist nicht zulässig. Zweitens: Das doppelte %-Zeichen ist in BAT-Dateien Vorschrift. Auf der Befehlsebene (wo die FOR-Konstruktion auch möglich ist) darf jedoch nur EIN %-Zeichen verwendet werden. Anmerkung: DOS ersetzt in einer BAT-Zeile vorab grundsätzlich doppelte %-Zeichen durch ein einfaches, und versucht in diesem Falle nicht, Umgebungsvariable oder Befehlsparameter einzusetzen. Danach sieht also eine FOR-Zeile genauso aus wie auf der Befehlsebene. Als Befehl in einer FOR-Konstruktion sind beliebige BAT-Befehle (auch CALL), DOS-Befehle oder Programmaufrufe möglich. Nur ein weiteres FOR ist nicht möglich. Noch ein Beispiel: for %%x in (DER.TXT DIE.DAT DAS.BLA) do COPY %%x A: Argumente mit Joker-Zeichen --------------------------- Sobald DOS in der Argument-Liste Fragezeichen oder Sternchen findet, wird das Argument als Dateiname verstanden (ggfs. mit Laufwerk und Pfad). Der Befehl wird dann für jeden Dateinamen ausgeführt, auf den der "Match-Code" paßt. Beispiele: FOR %%a in (C:\*.BAT) do type %%a FOR %%a in (*.TXT *.DAT) do echo %%a Im zweiten Beispiel werden alle Dateinamen mit den Zusätzen .TXT und .DAT auf dem Bildschirm ausgegeben. FOR %%f in (A:*.*) do DEL %%f Hier wird nicht etwa der Befehl "DEL A:*.*" ausgeführt, sondern ein DEL-Befehl für jede einzelne Datei! Trennzeichen in der Liste ------------------------- Außer Leerzeichen können Komma, Semikolon oder sogar das "=" Zeichen verwendet werden. Ein Argument darf also diese Zeichen nicht enthalten. Etwas ganz Merkwürdiges geschieht beim Schrägstrich. Ausprobieren: FOR %%a in (TEST/L12) do ECHO %%a. Dies wurde als undokumentiertes "Feature" für allerlei Tricks genutzt, funktioniert aber seit MS-DOS 7.x nicht mehr. Vielleicht war es doch nur ein Bug. Befehl mit IF ------------- Alternative Bedingungen (ODER) lassen sich mit einer FOR-Schleife einfacher darstellen als durch mehrfache IF-Zeilen, z.B.: FOR %%x in (A: a: B: b:) do IF "%1"=="%%x" goto OK QUIT echo Laufwerk %1 ist ungültig! :OK Hier wird getestet, ob der Befehlsparameter %1 ein gültiges Diskettenlaufwerk enthält. (Die Anführungszeichen verhindern Syntaxfehler, falls %1 leer ist. QUIT s. Lektion #11.) Ein bedingtes FOR kann ebenfalls verwendet werden, z.B.: if not "%1"=="" FOR %%a in (A: a: B: b:) do IF %1==%%a goto OK Leere Argumente --------------- Sind einzelne Argumente leer, wird der Befehl dafür nicht aus- geführt, z.B. hier: FOR %%a in (%1 %2 %3 %4 %5) do ECHO %%a Ist die ganze Argument-Liste leer, wird gar nichts ausgeführt. Es gibt auch keine Fehlermeldung, wenn hier z.B. %1 leer ist: FOR %%a in (%1) do irgendwas Vorsicht! --------- Für die Variable können Groß- oder Kleinbuchstaben verwendet werden, aber innerhalb einer FOR-Zeile muß man bei der Schreibweise bleiben! Das hier funktioniert nicht: FOR %%a in (*.*) do ECHO %%A ^ ^ FOR mit CALL ------------ Was eigentlich nicht geht, nämlich FOR-Verschachtelungen oder Ausführung MEHRERER Befehle, läßt sich durch CALL einer weiteren BAT-Datei in der FOR-Schleife realisieren. Bug: Errorlevel & GOTO ---------------------- Eine Errorlevel-Abfrage nach einer Programmausführung sieht so (ähnlich) aus: IF ERRORLEVEL 10 goto L-10 IF ERRORLEVEL 7 goto L-7 IF ERRORLEVEL 5 goto L-5 (u.s.w....) Zur Erinnerung: wegen der Größer/Gleich-Logik müssen Errorlevels absteigend abgefragt werden! Wäre es nicht auch möglich, dies per FOR-Schleife zu erledigen? Naheliegende Lösung: FOR %%a in (10,7,5,3,2,1,0) do IF ERRORLEVEL %%a GOTO L-%%a Wer es probiert, wird feststellen: es funktioniert nicht, und das hat folgenden Grund: Bei einem GOTO wird von DOS zwar sofort die jeweilige Sprungmarke aufgesucht, aber diese Stelle wird nur vorgemerkt, und der Ablauf wird dort erst dann fortgesetzt, wenn die Ausgangszeile komplett abgearbeitet ist (!) Leider kommt DOS nicht auf die Idee, daß eine FOR-Schleife mit dem ersten GOTO abgebrochen werden sollte. Statt dessen werden munter Sprungmarken gesucht (und die Adresse zur Fortsetzung des Ablaufs immer wieder überschrieben), solange die Bedingung WAHR ist - im obigen Beispiel also bis ganz zuletzt. Entgegen der üblichen Logik muß hier also die Reihenfolge der Abfrage umgekehrt werden: FOR %%a in (0,1,2,3,5,7,10) do IF ERRORLEVEL %%a GOTO L-%%a Wenn nun z.B. der Errorlevel 3 ist, dann ist die Bedingung bei 3 zum letzten Male WAHR, und die dabei gefundene Sprungmarke bleibt bis zur kompletten Abarbeitung der Schleife gültig. Aus diesem Grunde ist hier auch die Abfrage auf Errorlevel 0 ausnahmsweise sinnvoll, ja sogar unverzichtbar. WIN95, LFNFOR Bug: Bei Verwendung von Jokerzeichen in der Argumentliste werden nur DOS-Dateinamen und Pfade erkannt und behandelt. Es gibt zwar den neuen Befehl LFNFOR ON/OFF, um die Behandlung langer Dateinamen in einer FOR-Schleife ein/aus zu schalten, aber diese Funktion hat (zumindest bei DOS 7.0) einen Bug: Wenn die Klammer einen Verzeichnispfad enthält, wird nur für die erste Instanz (gefundene Datei) der Pfad mitgeliefert - die weiteren kommen OHNE Pfad. Verwendbar ist LFNFOR also nur im aktuellen Verzeichnis (also bei Dateibegriff ohne Pfad), oder aber wenn nur die erste Instanz gebraucht bzw. nur eine erwartet wird. =========== Umgebungsvariable, SET ================= Lektion #13 === In BAT-Abläufen lassen sich Variable benutzen, die als sogenannte "Umgebungsvariable" in einem besonderen Speicherbereich geführt werden. Auf Konzeption und Bedeutung dieser Umgebungsvariablen- Speicher soll hier nicht weiter eingegangen werden. Wichtig ist zunächst nur, daß dieser Bereich eine Liste von Zuweisungen enthält. Jede Zuweisung besteht aus einem Variablennamen und einer Zeichenfolge (String), getrennt durch das Gleich-Zeichen, z.B.: PROMPT=$p$g TEMP=C:\TEMP Der aktuelle Inhalt dieses Speichers kann jederzeit mit dem Befehl SET (ohne Angaben!) auf der DOS-Befehlsebene aufgelistet werden. COMMAND.COM bedient sich der Umgebungsvariablen, um bestimmte Informationen zu ermitteln, z.B. die Verzeichnispfade, in denen Programme gesucht werden sollen (PATH) oder die Darstellung der Eingabeaufforderung auf der Befehlsebene (PROMPT). Aber auch andere Programme können diese Informationen nutzen. Die wichtigste Verwendung bietet sich jedoch in BAT-Dateien: * Mit der SET-Anweisung können neue Zuweisungen aufgenommen, bestehende geändert oder gelöscht werden (möglich auch auf der Befehlsebene). Beispiel: SET WORT=das (neue Zuweisung oder Änderung) SET WORT= (Löschung: Leer-Zuweisung) * Durch Angabe des Variablennamens, eingeschlossenen in Prozent- zeichen, kann die aktuelle Zuweisung an jeder beliebigen Stelle der BAT-Datei eingesetzt werden. (Auf der Befehlsebene können diese Variablen erst seit MS-DOS 7 verwendet werden.) Beispiel: ECHO Die Variable WORT enthält "%WORT%" Im BAT-Ablauf untersucht DOS jede Zeile vor der Ausführung auf %- Zeichen, um Variable durch die zugewiesene Zeichenfolge zu ersetzen. Dabei ist es gleichgültig, ob sich die Variable in einem Text, einer Anweisung, einem GOTO-Ziel oder in sonstigen Angaben befindet. Ausgenommen sind nur Labels. Ist eine Variable nicht vorhanden, wird nichts eingesetzt, d.h. der %...% Ausdruck wird einfach entfernt. Hinweis: Um das Prozentzeichen in einem Text zu zeigen, muß es verdoppelt werden. Beispiel: ECHO Zuzüglich 7%% MwSt. Regeln für Variablen-Namen --------------------------- Bei Variablen-NAMEN wird Groß-/Kleinschreibung NICHT unterschieden (es wird generell in Großbuchstaben umgewandelt). Die zugewiesene Zeichenfolge wird dagegen immer unverändert gespeichert. Variablen-Namen dürfen nicht mit einer Ziffer beginnen, denn %0...%9 sind für Befehlsparameter reserviert. Bitte nicht versehentlich Variablennamen verwenden, die bereits von DOS oder von Programmen benutzt werden (wie z.B. PATH oder PROMPT). Beim SET-Befehl werden im Variablen-Namen auch Sonderzeichen und sogar Leerzeichen akzeptiert. Um Problemen aus dem Wege zu gehen, sollten aber nur Zeichen verwendet werden, die auch in Dateinamen gültig sind (ausgenommen "%"). Eine besondere Falle für Ahnungslose ist das Leerzeichen am Ende des Namens: SET TEST = JA ^ Hier ist der Variablen-Name nicht "TEST", sondern "TEST ", und die Verwendung von %TEST% funktioniert natürlich nicht... Also: zwischen Name und "=" bitte KEIN Leerzeichen! Hinweis: WINDOWS setzt einige Variable mit klein geschriebenem Namen, z.B. windir=C:\WINDOWS. Damit können diese Variable mit dem SET-Befehl weder verändert noch gelöscht werden. Seit MS-DOS 7 können diese Variablen aber wenigstens verwendet werden, wobei die Schreibweise (groß/klein) egal ist (%windir" oder %WINDIR%). Inhalt der zugewiesenen Zeichenfolge ------------------------------------ Mit SET wird der Variablen der gesamte Rest der Zeile zwischen dem Gleichzeichen und dem Zeilenende (CR) zugewiesen. Die Zeichenfolge kann also auch aus mehreren Wörtern bestehen. Beispiel: SET TEXT=Bitte Taste drücken! Auch Leerzeichen nach dem "=" sowie eventuelle Leerzeichen am Ende der Zeile (falls der Editor sowas nicht unterdrückt) sind Teil der zugewiesenen Zeichenfolge! Es gibt also keinerlei Begrenzungszeichen. DOS nimmt praktisch jedes Zeichen, sogar Control-Codes. Nur ein weiteres "=" in der Zeichenfolge wird reklamiert (Syntax-Fehler). Eine Variable kann auch eine ganze Pararmeter- oder Argument-Liste enthalten, die sich dann mit CALL oder FOR wieder zerlegen läßt. %PATH% ist so eine Liste. Beispiele: FOR %%a in (%PATH%) do ECHO %%a FOR %%a in (%PATH%) do if exist %%a\ARJ.EXE set ARJ_PATH=%%a Anmerkung: Bitte an die Länge der PATH-Variablen denken!. Die Zeile darf NACH dem Einsetzen der Variablen maximal 127 Zeichen lang sein, jedenfalls bis MS-DOS 6.xx. Seit MS-DOS 7 sind bis zu 1023 Zeichen möglich (sofern nicht ein kleinerer Wert mit COMMAND Option /L festgelegt wurde). Verkettung, Kombinationen ------------------------- Natürlich kann die zugewiesene Zeichenfolge ihrerseits Variable enthalten, besser gesagt: die aktuellen Zuweisungen von Variablen. denn diese werden ja vor Interpretation der Zeile eingesetzt. Beispiele: SET X=%X%/D SET PATH=%PATH%;C:\XYZ FOR %%x in (A a B b) do IF %LW%==%%x set LW=%LW%: ^ Variable und IF --------------- Solange eine Variable nur ein einfaches Wort enthält, können IF-Abfragen wie bei Befehlsparametern gemacht werden. Aber auch hier gelten die Grundregeln: * Groß-/Kleinschreibung wird unterschieden * Leere Variable gefährden die Syntax Immer daran denken, daß DOS erst dann anfängt, eine Zeile zu interpretieren, nachdem alle Variablen eingesetzt sind. Zur Abfrage auf leere Variable bzw. von möglicherweise leeren Variablen siehe Lektion #9. Beispiele: IF "%LW%"=="A:" goto OK IF [%LW%]==[] goto FEHLER Wenn allerdings eine Variable mehrere Wörter enthält (getrennt durch Leerzeichen, Komma, Semikolon), dann wird's gefährlich. * Mehrere Wörter NACH dem "==" bringen die Syntax durcheinander (verglichen wird ohnehin nur das erste Wort). * Bei mehreren Wörtern VOR dem "==" gibt es zwar keinen Fehler, aber es wird nur das erste Wort zum Vergleich herangezogen!! Ausprobieren: IF DAS NICHT==DAS echo Vergleich positiv Mit anderen Worten: IF-Abfragen sind in diesen Fällen tabu! Einzige Ausnahme: die Abfrage auf leere Variable funktioniert trotzdem, z.B.: IF [%VAR%]==[] goto ... Mal nachdenken warum. Verfügbarer Speicherplatz -------------------------- Der Speicherplatz für Umgebungsvariable ist begrenzt. Es wird daher dringend empfohlen, am Ende einer BAT-Datei alle nicht mehr benötigten Variablen zu löschen, damit kein Müll angehäuft wird. Mit FOR geht das ganz elegant - Beispiel: FOR %%a in (DATEI EL X Y Z) do SET %%a= Wieviel Platz noch frei ist, kann man DOS leider nicht so ohne weiteres entlocken. (Dafür gibt es aber kleine Utilities.) Da der Speicherplatz COMMAND.COM zugeordnet ist, kann die Größe des Speichers nur beim Laden des Befehlsprozessors beeinflußt werden. Dazu dient die Option /E der SHELL-Anweisung in der CONFIG.SYS - Beispiel (800 Bytes gewünscht): SHELL=C:\COMMAND.COM /P /E:800 Schaut mal bei HELP COMMAND nach... Weitere COMMAND-SHELL --------------------- Beim Laden einer weiteren COMMAND-SHELL wird ein eigener Speicher- bereich für Umgebungsvariable angeglegt. In diesen werden alle Zuweisungen der ersten SHELL kopiert. Aber umgekehrt wird nach Verlassen der SHELL (mit dem EXIT-Befehl) nichts übernommen! Standardmäßig wird von DOS nur recht wenig freier Speicher in einer weiteren COMMAND-Shell zur Verfügung gestellt. Erst seit MS-DOS 7 wird die Größe des Bereichs übernommen, so daß die gleiche Menge an freiem Speicher verfügbar ist. Bei Bedarf kann aber auch bei jeder weiteren Shell die Option /E verwenden werden, wobei natürlich der bereits verbrauchte Speicher (s.o.) zu berücksichtigen ist. Oft wird jedoch die COMMAND-Shell von einem Programm (z.B. NC) bereitgestellt, das dann auch für die Speichergröße zuständig ist. Gute Programme schaffen ausreichenden Speicherplatz, oder lassen die Größe per Setup einstellen. Für die COMMAND-Shell unter WIN 3.x läßt sich die Größe des Bereichs in der SYSTEM.INI, [NonWindowsApp], CommandEnvSize=.... einstellen. Bei WIN95: s. Eigenschaften/Speicher. System-Variable --------------- Von DOS bzw. COMMAND.COM werden folgende Variable benutzt: PATH Suchpfade für ausführbare Dateien TEMP Verzeichnis für temporäre Dateien COMSPEC Befehlsprozessor (COMMAND.COM) mit vollständigem Pfad PROMPT Eingabeaufforderung auf der Befehlsebene DIRCMD für DIR Optionen (ab DOS 5.0) CMDLINE (WIN95) windir winbootdir =========== Umleitung: Ausgabe ===================== Lektion #14 === Umleiten lassen sich Bildschirm-Ausgaben und Tastatur-Eingaben durch Verwendung folgender Symbole: > Ausgabe in Datei oder an ein Gerät umleiten < Eingabe aus Datei oder von einem Gerät holen | Ausgabe direkt in eine Eingabe leiten Umleitungen sind sowohl auf der Befehlsebene als auch in BAT-Dateien möglich. In dieser Lektion soll es zunächst um die Ausgabeumleitung gehen. Das Prinzip wurde bereits in Lektion #3 (ECHO-Umleitung) beschrieben. Beispiele: ECHO Dieser Satz wird in die Datei TEST geschrieben > TEST ECHO Dieser Satz wird an die Datei TEST angehängt >> TEST Eine eventuell vorhandene Datei wird durch den einfachen Pfeil gelöscht, während beim doppelten Pfeil am Ende angehängt wird. Grundsätzlich lassen sich auch die Bildschirm-Ausgaben von anderen Programmen oder DOS-Befehlen umleiten, z.B.: FIND "49-89-" NODE\NODELIST.001 > MUC.LST Das Ergebnis der Suche, das standardmäßig auf dem Bildschirm erscheint, wird hier in die Datei MUC.LST geschrieben. WICHTIG: Nicht alle Bildschirm-Ausgaben können umgeleitet werden. ------- Voraussetzung ist, daß der Output vom Programm über die DOS- STANDARD-AUSGABE vorgenommen wird. Nicht umleiten lassen sich: * Ausgaben über das BIOS oder direkt in den VIDEO-RAM-Speicher * Ausgaben über die STANDARD-FEHLER-AUSGABE Die STANDARD-FEHLER-AUSGABE geht immer auf den Bildschirm, damit der Benutzer auch bei umgeleiteten Ausgaben über eventuelle Fehler sofort informiert wird. Dazu das folgende Beispiel: copy DIESE.DAT A: > AUSGABE.TXT Die Bestätigung von DOS, "n Datei(en) kopiert", wird hier in die Datei AUSGABE.TXT umgeleitet. Dies gilt auch für den Fall, daß die zu kopierende Datei nicht existiert: "0 Datei(en) kopiert". Die zusätzliche Fehlermeldung "Datei nicht gefunden" erscheint dann jedoch auf dem Bildschirm. Ob und welche Ausgaben eines Programmes sich umleiten lassen, muß man gegebenenfalls durch Ausprobieren herausfinden. Umleitung an andere Geräte -------------------------- Geräte-Namen können unter DOS wie Dateinamen verwendet werden. Die Ausgabe kann also auch z.B. an den Drucker geschickt werden Beispiel: type DIESEN.TXT > PRN (= copy DIESEN.TXT PRN) arj l ARCHIV > LPT1 (Inhaltsverzeichnis an Drucker) Umleitung > NUL --------------- NUL ist ein nicht existierendes Gerät, das aber benutzt werden kann, um Ausgaben ins Nichts zu schicken. Damit lassen sich oft unerwünschte Ausgaben in BAT-Abläufen unterdrücken, sofern(!) es sich um eine Standard-Ausgabe handelt. Störende Fehlermeldungen, z.B. bei DEL ("Datei nicht gefunden") verschwinden damit nicht. Sie lassen sich am besten durch geeignete Abfragen unterdrücken: IF exist %DATEI% del %DATEI% Anfügen in Dateien ------------------- Bei Verwendung des doppelten Pfeiles bitte beachten: * Wenn die Datei noch nicht existiert, wirkt der doppelte Pfeil wie ein einfacher. * Beim ersten Mal, z.B in einer FOR-Schleife, sollte die Datei einen definierten Zustand haben (evtl. vorher löschen), z.B.: del LISTE.TMP for %%a in (*.TXT) do ECHO %%a >> LISTE.TMP * Falls die vorhandene Datei ein EOF-Zeichen (Control-Z) am Ende hat, wird dieses von DOS entfernt. Eingaben bei Ausgabe-Umleitung ------------------------------ Wenn ein Programm bei umgeleiteter Ausgabe eine Eingabe erwartet, steht man oft im Dunklen, weil die Eingabehinweise ja auch umgeleitet werden. Dies kann z.B. bei CHKDSK /F passieren oder auch bei DIR, wenn da jemand die Umgebungsvariable DIRCMD=/P gesetzt hat... Wie sich die Eingabe umleiten (also aus einer Datei holen) läßt, kommt in der nächsten Lektion. Hinweise -------- * Wenn es nichts umzuleiten gibt, wird trotzdem die angegebene Datei erstellt, und zwar mit Null Bytes (!) Das kann man gezielt nutzen, z.B.: REM > DATEI * Normalerweise werden auf dem Bildschirm Zeilen ausgegeben, so daß auch in der Datei Zeilen mit CR+LF am Ende gespeichert werden. Das muß aber nicht so sein und hängt vom jeweiligen Programm ab. * Der Umleitungsausdruck, also Pfeil(e) mit Dateiname/Gerät, muß nicht unbedingt hinter dem Befehl stehen. DOS nimmt vor der Verarbeitung eines Befehls den Umleitungsausdruck heraus, ganz egal, wo er gefunden wird. In den folgenden Beispielen ist das Ergebnis immer das selbe: ECHO Das ist ein Test> DATEI >DATEI ECHO das ist ein Test ECHO Das> DATEI ist ein Test Auch bei versehentlichen Umleitungszeichen geht DOS ganz konsequent vor, ob es nun Sinn macht oder nicht... * Bei Umleitung mit einfachem Pfeil in einem bedingtem Befehl.. z.B. IF errorlevel 1 echo irgendwas > DATEI wird die Ausgabedatei neu angelegt, BEVOR die Bedingung geprüft wird. D.h. wenn die Bedingung NICHT WAHR ist, wird trotzdem die Ausgabedatei mit 0 Bytes erzeugt. Falls die Datei bereits vorhanden war, wird sie damit zerstört. * Die Datei für die Ausgabe-Umleitung darf nicht den Platzhalter einer FOR-Schleife (z.B. %%a) enthalten, da die Umleitungsdatei angelegt wird, bevor DOS die FOR-Schleife zur Kenntnis nimmt! Das hier geht nicht: for %%a in (*.TXT) do echo irgendwas >> %%a * Eine Umleitung beim Aufruf einer BAT-Datei ist wirkungslos. Wer auf diese Weise ALLE Ausgaben einer BAT-Datei umleiten will, muß dazu eine weitere COMMAND-Shell starten, z.B.: COMMAND /C X.BAT > DATEI (Option /C s. COMMAND /?) =========== Umleitung: Eingabe, Pipe =============== Lektion #15 === Die Eingabe-Umleitung ist das Gegenstück zur Ausgabe-Umleitung und verwendet den Pfeil nach links. Dabei werden Eingaben, die eigentlich von der Tastatur erwartet werden, aus einer Datei eingelesen. Voraussetzung ist natürlich, daß die angegebene Datei mit dem erforderlichen Inhalt existiert. Beispiel: DEL A:*.* < J.TXT Da DOS hier nachfragt "Sollen alle Dateien...gelöscht werden? (J/N)" muß die Datei J.TXT ein "J" und ein CR enthalten, also eine Zeile mit "J" und dem üblichen Zeilenabschluß. Falls die Datei weitere Daten enthält, werden diese ignoriert, da der DEL-Befehl ja keine weiteren Eingaben erwartet. Grundsätzlich können aber auch mehrfache Eingaben für ein Programm nacheinander aus den einzelnen Zeilen einer Datei entnommen werden. Dies läßt sich z.B. beim Programm DEBUG nutzen, um ein ganzes Skript von Befehlen abzuarbeiten (DEBUG < Datei). Noch ein Beispiel: MORE < SOME.TXT Das DOS-Programm MORE gibt die Eingabezeilen auf dem Bildschirm aus, und zwar mit Stop nach jeder vollen Seite. Das macht natürlich nur Sinn, wenn die Eingabe aus einer Datei kommt. Standard Input -------------- Entsprechend der Ausgabe-Umleitung ist auch bei der Eingabe eine Umleitung nur möglich, wenn der Input des Programms über die STANDARD-EINGABE angefordert wird. Daß es sich hierbei um die Tastatur handelt, ist klar, aber das betreffende Programm muß die üblichen DOS-Funktionen benutzen. Bei Verwendung von BIOS-Funktionen kann der Input nicht umgeleitet werden. Quelle für eine Input-Umleitung kann auch ein Gerät sein, z.B. COM1. Ausgabe direkt in Eingabe leiten (PIPE) --------------------------------------- Im obigen DEL-Beispiel wurde angenommen, daß die Datei J.TXT für die Eingabe-Umleitung bereits vorhanden ist. Natürlich kann sie auch unmittelbar vorher per ECHO-Umleitung produziert werden: ECHO J> J.TXT DEL A:*.* < J.TXT del J.TXT Das ist jedoch ziemlich umständlich, da auch noch die Hilfsdatei hinterher gelöscht werden muß. Einfacher geht's mit der direkten Methode: ECHO J| del A:*.* Das "|" bewirkt, daß der Output von der linken Seite als Eingabe für die rechte Seite übernommen wird. DOS produziert dazu zwar auch eine Zwischendatei (im temporären Verzeichnis %TEMP%), aber man braucht sich um deren Namen und um das anschließende Löschen nicht zu kümmern. Solche "PIPES" sind eigentlich dafür gedacht, ganze Text-Dateien zu verarbeiten. Das Programm SORT z.B. macht wie MORE (s.o.) auch nur Sinn, wenn es mit Umleitungen benutzt wird. Beide Programme erwarten (standardmäßig) den Input von der Tastatur und senden den Output auf den Bildschirm. Der folgende Befehl sortiert die Datei ASCII.TXT mit SORT /R in absteigender Folge und gibt das Resultat seitenweise auf dem Bildschirm aus (MORE): SORT /R < ASCII.TXT | MORE Anordnung im Befehl ------------------- Ein-/Ausgabeumleitung und mehrere Pipes können in einem Befehl kombiniert werden. Für die richtige Reihenfolge der Angaben ist nur zu beachten, daß mit "|" (Pipe) verbundene Programme immer von links nach rechts abgearbeitet werden. Befehlsparameter und Optionen müssen unmittelbar auf den zugehörigen Befehl folgen. Umleitungsausdrücke mit Pfeil nach links/rechts sind zwangsläufig dem ersten bzw. letzten Programm (Befehl) zugeordnet, ganz gleich, wo sie plaziert werden. Hinweise -------- Vorsicht bei der Eingabe-Umleitung für Programme, die ganz bestimmte Eingaben erwarten: Falls die Eingabedatei falsche oder gar keine Angaben enthält, läßt sich auch mit der Tastatur nichts mehr korrigieren, weil die ja ignoriert wird. Mit etwas Glück geht vielleicht noch ein Control-BREAK, sonst ist ein Warmstart fällig. Und: bitte nicht für Eingabe- und Ausgabeumleitung die selbe Datei verwenden, z.B.: Befehl < DATEI > DATEI Da sich DOS beeilt, die Ausgabedatei neu anzulegen, ist die Eingabedatei hin, bevor sie gelesen werden kann. Anmerkung: unter DOS 6.xx funktioniert das zwar doch, aber unter DOS 7.x schon wieder nicht mehr.... Sichere Methode: type DATEI | Befehl > DATEI Doppelte Anführungszeichen --------------------------- Die Umleitungs- und PIPE-Symbole werden von DOS innerhalb von doppelten(!) Anführungszeichen NICHT als solche interpretiert, sondern wie normale Textzeichen behandelt, z.B.: ECHO " irgendwas > datei " Eine brauchbare Verwendung dürfte schwer zu finden sein, aber immerhin funktioniert z.B. ein FIND ">".... ohne Probleme. Achtung: Bug! ------------- Anweisungen mit PIPE ("|") dürfen nicht bedingt sein, z.B.: ------------- IF %1==X echo.|date MS-DOS reagiert je nach Version und Konfiguration (SHARE, WIN) mit ziemlich unbrauchbaren Fehlermeldungen, oder es passiert einfach gar nichts. Falls nötig, also eine IF...GOTO Konstruktion verwenden! Ähnliche Probleme gibt es auch bei der FOR-Schleife. Der Grund: MS-DOS legt die Pipes und Umleitungen an, BEVOR die gesamte Zeile interpretiert wird, und nicht erst für die einzelnen Instanzen der FOR-Schleife. Siehe auch Hinweis zur Ausgabe-Umleitung in Lektion #14. =========== Errorlevel in Variable ================= Lektion #16 === DOS erlaubt es leider nicht, den Errorlevel in Form einer Variablen zu verwenden. Zwar gibt es seit MS-DOS 7.x die undokumentierte COMMAND Option /Z, mit der nach jedem Programm der Errorlevel auf dem Bildschirm ausgegeben wird, aber die Übernahme in eine Variable wäre oft nützlicher. Zur Lösung des Problems gibt es einmal die brutale Methode mit 255 einzelnen Abfragen und SET-Befehlen. Auf die etwas feinere Art werden FOR-Schleifen benutzt, wobei das Ergebnis schrittweise aus drei Ziffern zusammengesetzt wird. Um zu verstehen, wie das funktioniert, soll erst mal der Errorlevel von 0...9 (bzw. 10) ermittelt werden: ------------------------------------------------------------------ FOR %%e in (0 1 2 3 4 5 6 7 8 9) do IF Errorlevel %%e set EL=%%e IF errorlevel 10 set EL=10 oder höher ECHO Errorlevel: %EL% ------------------------------------------------------------------ Der Variablen EL werden hier nacheinander die Werte 0,1,2,3... zugewiesen, aber nur so lange wie die Errorlevel-Abfrage WAHR ist. Wenn also z.B. der Errorlevel 5 ist, dann passiert in der Schleife ab 6 nichts mehr, und in der Variablen bleibt die 5 hängen. Immer daran denken: IF Errorlevel n bedeutet: IF Return-Code >= n Errorlevels müssen in FOR-Schleifen immer in aufsteigender Folge abgefragt werden (auch in Verbindung mit GOTO, s. Lektion 12). Um zwei Ziffern (also 00..99) zu ermitteln, braucht man auch zwei Schleifen: ------------------------------------------------------------------ :: Zehner ermitteln FOR %%z in (0 1 2 3 4 5 6 7 8 9) do IF Errorlevel %%z0 set EL=%%z :: Einer anhängen FOR %%e in (0 1 2 3 4 5 6 7 8 9) do IF Errorlevel %EL%%%e set EL=%EL%%%e IF errorlevel 100 set EL=100 oder höher ECHO Errorlevel: %EL% ------------------------------------------------------------------ Die vielen %-Zeichen sind etwas verwirrend, darum hier im Detail: In der ersten Schleife wird Errorlevel %%z0 abgefragt, also %%z (aus der Liste) mit einer angehängten Null - ergibt 00,10,20.... In EL wird aber zunächst nur die Zehner-Ziffer gespeichert. In der zweiten Schleife wird Errorlevel %EL%%%e abgefragt, also zusammengesetzt aus %EL% (der bereits produzierte Zehner) und %%e (Einer aus der Liste). Dazu ein Hinweis: Umgebungsvariable in einer FOR-Zeile werden von DOS nur einmalig vor Ausführung der Schleife eingesetzt. Obwohl also in der zweiten Schleife EL ständig verändert wird, hat dies keinen Einfluß mehr auf den dabei geprüften Wert %EL%. Die Hunderter könnte man ja nun auf die gleiche Weise ermitteln. Aber da wird die Sache etwas komplizierter, weil dann zwangsläufig Errorlevels über 255 abgefragt werden - und dabei gibt es Probleme: DOS subtrahiert kommentarlos 256 (verwendet also immer den Rest aus Zahl dividiert durch 256). Die Abfrage IF Errorlevel 260 bewirkt also: IF Errorlevel 4 Aus diesem Grund muß extra dafür gesorgt werden, daß die Ziffern- Liste nur (0 1 2 3 4 5) enthält, wenn die Schleife über 255 hinausgehen könnte. Dazu werden die Ziffern von 6 bis 9 in einer Variablen (%!%) gespeichert, die bei Bedarf leer bleibt. Dies ist die komplette Routine: --------------------------------------------schnipp--------------- @echo off set != :: Hunderter FOR %%h in (0 1 2) do IF Errorlevel %%h00 set EL=%%h :: & Zehner IF not Errorlevel 200 set !=6 7 8 9 FOR %%z in (0 1 2 3 4 5 %!%) do IF Errorlevel %EL%%%z0 set EL=%EL%%%z :: & Einer IF not Errorlevel 250 set !=6 7 8 9 FOR %%e in (0 1 2 3 4 5 %!%) do IF Errorlevel %EL%%%e set EL=%EL%%%e :: ECHO Errorlevel: %EL% set != --------------------------------------------schnapp--------------- Wer das Ganze zu kompliziert findet, kann ja einfach die Routine ausschneiden und daraus eine BAT-Datei machen, z.B. ELEVEL.BAT. Diese kann dann jederzeit nach einem Programm per CALL aufgerufen werden, um den Errorlevel-Wert auf dem Bildschirm zu zeigen oder um %EL% sonstwie zu verwenden. (Natürlich kann ELEVEL.BAT auch auf der Befehlszeile nach irgendeinem Programm benutzt werden.) Bitte beachten: die Variablen EL und ! sollten in der aufrufenden Batch nicht für andere Zwecke verwendet werden. EL muß später noch gelöscht werden. =========== ANSI Sequenzen (Bildschirm) ============ Lektion #17 === Mit den berühmten ANSI-Sequenzen lassen sich Farben und Cursor- Steuerungen in BAT-Dateien realisieren. Außerdem können Tasten umbelegt bzw. mit Befehlen belegt werden (nächste Lektion) und der Video-Modus gewählt werden (für Batch nicht zu gebrauchen, Näheres s. DOS-Handbuch). Voraussetzung ist der Konsol-Treiber ANSI.SYS (oder ein Ersatz), der in der CONFIG.SYS installiert wird. Über diesen Treiber gehen alle DOS-Bildschirmausgaben und -Tastatureingaben, so daß hier bestimmte Bildschirm-Aktionen oder Tasten-Umwandlungen gesteuert werden können. Die dazu erforderlichen Befehle sind irgend wann einmal vom American National Standards Institute ("ANSI"), also einer Art DIN-Behörde der USA, genormt worden. Die Befehle werden als "ANSI-Sequenzen" per DOS-Ausgabe an den Bildschirm geleitet und vom Konsol-Treiber abgefangen. Damit ANSI.SYS einen Befehl erkennt, muß dieser mit den zwei Code-Bytes ESCAPE und "[" beginnen. Danach folgen die Befehlsinformationen, und als letztes immer ein Buchstabe, der die Art des Befehls bestimmt. Beim ESCAPE-Zeichen gibt's ein kleines Problem: In der BAT-Datei muß ein Byte mit dem Wert 27 (dez) bzw. 1B (hex) gespeichert werden. Wie das eingegeben wird, hängt vom jeweiligen Editor ab. Eines der folgenden Verfahren führt normalerweise zum Erfolg: * ALT gedrückt halten und Dezimal-Code (27) im Ziffernblock der Tastatur eingeben * Prefix Control+P, um zu signalisieren, daß der anschließende Control-Code (ESC-Taste oder ALT-Prozedur wie oben) als Zeichen gespeichert werden soll. Was dann auf dem Bildschirm erscheint, ist ein kleiner Pfeil nach links (von IBM wurden auch den Control-Codes bestimmte Zeichen zugeordnet). Manche Editoren zeigen auch ^[ - also eine 2-Byte- Sequenz, wobei die eckige Klammer zufällig das selbe Symbol ist, das als nächstes Byte der ANSI-Sequenz folgen muß. !! Da hier in diesem Text das ESC-Zeichen nicht verwendet werden !! kann, wird in allen folgenden Beispielen das Zeichen "#" an !! dessen Stelle gesetzt, also z.B.: #[40;37m ^-------------- hier ESC-Code! Grundsätzlicher Aufbau einer ANSI-Sequenz ------------------------------------------ Nach den beiden Erkennungsbytes - #[ - folgen dezimale Zahlenangaben (0...255), und zwar entweder mehrere, nur eine oder auch gar keine. Falls mehrere Zahlenangaben erforderlich sind, müssen sie durch ein Semikolon getrennt werden. Die gesamte Sequenz darf keine Leerzeichen enthalten. Den Abschluß der ANSI-Sequenz bildet ein Buchstabe. Groß-/Klein- schreibung wird hier unterschieden - also aufpassen! Beispiele: #[K #[3A #[30;47;1m Die ANSI-Sequenzen können an beliebiger Stelle in Textausgaben eingesetzt werden, normalerweise im ECHO-Befehl, oder in Dateien, die z.B. per TYPE ausgegeben werden. Grundsätzlich können die Sequenzen aber in DOS-Bildschirmausgaben von jedem Programm verwendet werden. ANSI-Sequenzen sind nicht auf der DOS-Befehlsebene nutzbar, da ESCAPE hier nicht als Zeichen akzeptiert wird. Funktionen: Cursor ------------------ * Cursor relativ bewegen, ausgehend von der aktuellen Position: #[1A 1 Zeile aufwärts #[3B 3 Zeilen abwärts #[25C 25 Spalten nach rechts #[12D 12 Spalten nach links Bei zu großen Werten wird der Cursor an die äußerste mögliche Position gesetzt (!). Bei fehlenden Werten gilt 1. #[80D an den Zeilenanfang (egal von wo) #[A 1 Zeile aufwärts * Cursor absolut setzen (Zeile;Spalte). #[1;1H Zeile 1, Spalte 1 (linke obere Ecke) #[12;33H Zeile 12, Spalte 33 Bei ungültigen Angaben wird der Befehl ignoriert. Fehlende Angaben werden durch 1 ersetzt, z.B.: #[H Cursor Home (linke obere Ecke) Zu allen Cursor-Positionierungen bitte beachten: Eine ECHO- Ausgabe wird immer mit CR+LF abgeschlossen. Der Cursor geht also an den Anfang der nächsten Zeile. Soll ein Text an eine bestimmte Stelle positioniert werden, muß dieser unmittelbar auf den Cursor-Befehl folgen, z.B.: ECHO #[1;30Hhier ist Position 30 in der ersten Zeile ----- * Position speichern/wiederherstellen #[s ANSI merkt sich die aktuelle Position #[u Gespeicherte Position wird wiederhergestellt Wenn der Bildschirm zwischendurch scrollt, stimmt die Position natürlich nicht mehr. Funktionen: Löschen -------------------- #[2J Bildschirm löschen und Cursor Home (die "2" ist eine Konstante!) #[K Zeile ab aktueller Position löschen (großes "K") Funktion: Farben ---------------- Für Farben und "Attribute" gibt es folgende Zahlen-Codes: Zeichen: Grund: Farbe: | Attribute 30 40 schwarz | 0 weiß auf schwarz 31 41 rot | 1 helle Zeichen 32 42 grün | 5 blinkende Zeichen 33 43 braun/gelb | 7 schwarz auf weiß 34 44 blau | 8 schwarz auf schwarz 35 45 magenta (violett) | 36 46 zyan (türkis) | 37 47 weiß | Alle Farb-Sequenzen werden durch ein kleines "m" abgeschlossen. Beispiele: #[0m normalisieren (weiß auf schwarz) #[0;1m hell weiß auf schwarz #[37;40;1m das selbe #[31;40m rot auf schwarz #[31;44;1m hell rot auf blau Alle Farben sowie die Attribute 1 und 5 können auch einzeln angegeben werden, wenn die übrigen Werte unverändert bleiben sollen: #[37m weiße Zeichen, Grund und Helligkeit bleiben #[1m helle Zeichen, Farben bleiben Achtung! Die Funktionsweise der Attribute ist nicht besonders logisch. * Attribut 0 (Null) setzt nicht nur alle anderen Attribute zurück, sondern auch die Farben (weiß auf schwarz). * Um 1 (hell) oder 5 (blinkend) zurückzusetzen, müssen also bei Bedarf die Farben erneut angegeben werden (und zwar NACH der Null), z.B.: #[0;36;40m normalisieren, türkis auf schwarz * Attribut 7 soll offiziell "invertieren", macht aber immer schwarz auf weiß, egal was vorher war. Die gesetzten Werte für hell und blinkend bleiben erhalten. * Attribut 8 soll "verstecken" (unsichtbar machen), aber falls Attribut 1 gesetzt war, wird *hell* schwarz auf schwarz produziert (und das ist nicht unsichtbar). Die ANSI-Farbbefehle gelten für alle folgenden Zeichen-Ausgaben sowie für Löschbefehle und neue Zeilen beim Scrollen. (Mit dem Farbbefehl selbst wird also zunächst auf dem Bildschirm nichts verändert). Beispiel: #[37;44;1m#[2J hiermit wird der Bildschirm für hell weiße Zeichen auf blauem Grund vorbereitet und dann gelöscht. ECHO off -------- Bei Verwendung von ECHO-Befehlen mit ANSI-Sequenzen sollte darauf geachtet werden, daß ECHO OFF ist, sonst werden alle Befehle doppelt an den Konsol-Treiber gegeben. ANSI-Grafik ----------- Für aufwendige Bildschirm-Gestaltungen empfiehlt es sich, Text und ANSI-Sequenzen in einer separaten ASCII-Datei unterzubringen, die dann per TYPE ausgegeben wird. Das macht die Batch-Datei übersichtlicher und geht außerdem schneller. Für ganz Eilige gibt es auch TYPE-Ersatzprogramme, die noch um ein Vielfaches schneller sind als DOS. Übrigens: ANSI-Grafiken und spezielle Software gibt's in Mailboxen. Konsol-Treiber -------------- Als Ersatz für ANSI.SYS sind diverse Alternativen im Umlauf, die - wie könnte es anders sein - schneller sind, zusätzliche Funktionen bieten und weniger Speicher brauchen. Prompt ------ Auch bei der Definition des Prompts (PROMPT-Anweisung) können ANSI- Sequenzen eingebaut werden. Hier wird jedoch anstelle des ESCAPE- Codes die Zeichenfolge "$e" verwendet. Näheres s. DOS-Hilfe. Zum Schluß noch ein Goody: @echo off echo #[0;5m¦¦#[7m¦¦#[0m bitte warten! :: ^^----^^--------------------- ASCII Code 219 pause > nul (zum Testen) echo #[A#[K =========== ANSI Sequenzen (Tastatur) ============== Lektion #18 === In Lektion 17 wurde bereits darauf hingewiesen, daß sich mit ANSI- Sequenzen auch Tasten umdefinieren oder mit Befehlen belegen lassen. Die Anweisung dazu wird, ebenso wie alle anderen ANSI-Befehle, per DOS-Bilschirmausgabe an den Konsoltreiber geschickt. Abschluß-Buchstabe der Sequenz für Tasten-Umbelegung ist das keine "p". Nochmal der Hinweis (s. Lektion 17): !! Da hier in diesem Text das ESC-Zeichen nicht verwendet !! werden kann, wird in allen folgenden Beispielen das Zeichen !! "#" an dessen Stelle gesetzt, also z.B.: #[36;156p ^-------------- hier ESC-Code! In obigen Beispiel wird der ASCII-Tasten-Code 36 ("$") durch das "£"-Zeichen (Code 156) ersetzt. Anstelle der dezimalen Zahlen können hier aber auch die Zeichen selbst verwendet werden, und zwar in (einfachen oder doppelten) Anführungsstrichen: #["$";'£'p Funktionstasten --------------- Funktionstasten und sonstige Tasten, die kein ASCII-Zeichen abgeben (z.B. Cursor-Tasten) werden durch zwei Zahlen bestimmt, von denen die erste immer Null ist. Beispiel: #[0;59;0;80p Die Funktionstaste F1 (Code 59) wird mit ---- ---- Cursor abwärts (Code 80) belegt. Die Tasten-Codes sind in entsprechenden Tabellen (u.a. im DOS- Handbuch) zu finden. Es gibt auch kleine Utilities, die den Code jeder gedrückten Taste zeigen. Tastenfolge zuweisen -------------------- Die neue Tasten-Belegung darf auch mehrere Zeichen oder Tasten-Codes enthalten, und zwar als Folge von dezimalen Werten oder als String in Anführungszeichen (auch gemischt). #[0;59;"chkdsk";13p ---- ----------- Die Taste F1 ist hier mit dem Befehl CHKDSK belegt, inklusive anschließendem ENTER (CR: ASCII Code 13). Umbelegung rückgängig machen ------------------------------ Wenn keine neue Tasten-Zuweisung angegeben wird, stellt ANSI.SYS den Original-Code der Taste wieder her. #["$"p Originalzustand der $-Taste #[0;59p F1-Taste liefert wieder den Code 59 Edit-Tasten bei DOS-Eingabe --------------------------- Funktionstasten sind unter DOS standardmäßig mit bestimmten Editier-Funktionen belegt, z.B. liefert die Taste F1 (ohne DOSKEY) schrittweise die Zeichen des letzten eingegebenen Befehls. Diese Standard-Funktionen werden natürlich durch Umbelegung per ANSI-Sequenz aufgehoben, können aber wieder aktiviert werden, indem der Taste der eigene Code zugewiesen wird. #[0;59;"copy "p eine Umbelegung #[0;59;0;59p DOS-Editierfunktion wiederherstellen #[0;59p KEINE Belegung (Taste liefert F1-Code) DOS- und BIOS-Input ------------------- Die Tasten-Umbelegungen per ANSI sind nur wirksam, wenn DOS-Input- Funktionen benutzt werden. Viele Programme verwenden jedoch BIOS- Aufrufe zur Abfrage der Tastatur, und diese gehen NICHT über ANSI.SYS. Die Umbelegungen sind wohl in erster Linie auf der Befehlsebene brauchbar. Noch ein Hinweis ---------------- Jede fremde ASCII-Datei kann über eine solche ANSI-Sequenz sogar die ENTER-Tasten mit einem gefählichen Befehl belegen ("ANSI-Bomben") Wer sich schützen will, verwendet einen ANSI-Treiber, der Tasten- Umbelegungen erst gar nicht (oder nur bedingt) zulässt. Eine andere Methode: den Buchstaben "p" in der ANSI.SYS in einen "privaten" Code abändern (DEBUG Adresse: hex 161). =========== CHOICE (DOS 6.+) ======================= Lektion #19 === Seit MS-DOS Version 6.0 wird ein Hilfsprogramm mitgeliefert, das in dieser oder ähnlicher Form (meist unter anderem Namen) bereits seit etlichen Jahren im Umlauf ist: CHOICE ("Auswahl"). CHOICE hält den Ablauf an und wartet auf eine Tasten-Eingabe, wobei die erlaubten Tasten im CHOICE-Befehl vorgegeben werden. Entsprechend der gedrückten Taste kann dann per Errorlevel-Abfrage verzweigt werden. Als Option gibt's die Möglichkeit, den Ablauf nach nn Sekunden automatisch fortzusetzen. Syntax ----------------------------------------------------------- CHOICE [/C[:]Tasten] [/N] [/S] [/T[:]c,nn] [Text] /C[:]Tasten Angabe der zulässigen Tasten. Standard ist JN. /N Keine Anzeige der zulässigen Tasten am Ende der Eingabeaufforderung /S Groß-/Kleinschreibung für Tasten wird beachtet. /T[:]c,nn Nach nn Sekunden wird Standardauswahl c ausgeführt. Text Eingabeaufforderung, die angezeigt wird. ERRORLEVEL ist auf die Position (1...) der gedrückten Taste aus der Tastenauswahl gesetzt. ------------------------------------------------------------------ Beispiel: CHOICE /C:JN weiter if errorlevel 2 goto ENDE DOS gibt folgenden Prompt aus: weiter [J,N]? ^^^^^^-------- wird gem. /C Angaben eingesetzt Da "J,N" Standard ist, kann in diesem Falle die Option /C auch weggelassen werden. Je nach gedrückter Taste wird der Errorlevel entsprechend der Position (1...) in der /C Option gesetzt. Mit "N" wird also im obigen Beispiel Errorlevel 2 gesetzt. Errorlevel 0 wird übrigens nie zurückgegeben. Bei Syntax-Fehlern wird Errorlevel 255 zurückgegeben, und der Ablauf wird ohne Pause fortgesetzt. Also: entweder zusätzlich Errorlevel 255 abfragen oder keine Fehler machen! Weitere Erläuterungen: /C[:]Tasten Die Zahl der zugelassenen Tasten ist nicht begrenzt. Es können aber nur ASCII-Zeichen als Tasten angegeben werden, ohne Trennzeichen dazwischen. Beispiel: CHOICE /C:NWA Nochmal, Weiter oder Abbrechen Control-Codes sind möglich, wenn sie als Zeichen dargestellt werden können, z.B. ESCAPE wie bei den ANSI-Sequenzen. ENTER und Leertaste sind nicht verwendbar. Text Was nicht mit einem Schrägstrich beginnt, wird als Text (Prompt, Eingabeaufforderung) auf dem Bildschirm ausgegeben. Der Text darf in (doppelten) Anführungszeichen angegeben werden. In diesem Falle sind auch Schrägstriche im Text erlaubt. /N Die zulässigen Zeichen in eckigen Klammern (plus Fragezeichen) werden mit /N nicht automatisch im Prompt hinzugefügt. (Option /N empfiehlt sich z.B. bei Verwendung von ESC.) /T[:]c,nn Nach nn Sekunden (maximal zweistellige Angabe!) wird automatisch fortgesetzt. Die Angabe c ist ein Buchstabe aus der /C Option. Nach Ablauf der Zeit wird der Errorlevel so gesetzt, als würde diese Taste gedrückt. Beispiel: CHOICE Weiter suchen /C:JN /T:N,5 (Hier kann die Option /C weggelassen werden, da JN Standard ist) Menues ------ Mit ECHO-Zeilen kann zuvor ein Menü ausgegeben werden, z.B.: echo 1 Mailer echo 2 Editor echo 3 Packer echo 4 Terminal echo. choice Auswahl (Ziffer), ESC=Ende /C:1234# /N :: hier ESC-Code (27) ----------------^ Durch zusätzliche Rahmen und ANSI-Farben läßt sich damit ein ganz passables Bild produzieren. Auch der Text in der CHOICE-Zeile darf ANSI-Sequenzen enthalten! =========== SETWORD.COM - Systeminformationen ====== Lektion #20 === Häufigstes Problem bei der Programmierung von Batch-Abläufen ist die Verwendung von System- und Datei-Informationen: Tagesdatum und Uhrzeit, Volume Label, aktuelles Verzeichnis oder Laufwerk, Verzeichnispfad einer Datei, Dateidatum und so weiter. DOS bietet hier leider keine fertigen Lösungen an. Sofern man nicht mit 4DOS arbeitet, gibt es folgende Möglichkeiten: (1) reine Batchlösungen, die meist recht aufwendig und schwer zu durchschauen sind, (2) kleine Utilities, von denen sich mit der Zeit eine ganze Menge ansammeln, (3) Multifunktionsprogramme, also eine Zusammenfassung vieler Funktionen in einem Programm. Hier soll eine Lösung vorgestellt werden, die eine Mischung aus allen dreien ist. Dazu wird ein kleines Programm (SETWORD.COM) in Verbindung mit normalen DOS-Funktionen und Umleitungen/PIPEs eingesetzt, so daß auch ein Lerneffekt für diesen Batchkurs dabei abfällt. Das nötige Programmm wird (als "DEBUG-Skript", s.u.) gleich mitgeliefert. SETWORD.COM liest per PIPE (|) den DOS-Output von Befehlen wie DIR, VOL, DATE, TIME etc. und entnimmt daraus das soundsovielte Wort - auch über mehrere Zeilen hinweg! Die Position des Wortes (1...) wird zu SETWORD angegeben - ohne Angabe gilt 1. Beispiel: VOL A: | SETWORD 6 Der Befehl VOL liefert z.B.: Datenträger in Laufwerk A: ist BACKUP -----1----- 2- ----3--- 4- -5- --6--- Damit nun das Wort im BAT-Ablauf verwendet werden kann, schreibt SETWORD einen entsprechenden SET-Befehl (per > Umleitung) in eine temporäre BAT-Datei, die dann per CALL ausgeführt wird, z.B.: VOL A: | SETWORD 6 > TMP.BAT In der TMP.BAT steht dann folgendes (gem. obigem Beispiel): SET %1=BACKUP Anstelle eines Variablennamens wird immer %1 geschrieben, d.h. der Name ist selbst variabel und wird beim CALL als Parameter angegeben, also: VOL A: | SETWORD 6 > TMP.BAT call TMP.BAT LABEL :: ^^^^^--------- Name der Variablen Nun kann %LABEL% abgefragt oder sonstwie verwendet werden. Ohne Umleitung der Ausgabe erscheint der SET-Befehl auf dem Bild- schirm - zum Testen genau das Richtige. Ausprobieren: VOL | SETWORD 4 (aktuelles Laufwerk) CD | SETWORD 1 (aktuelles Verzeichnis) DIR Datei | SETWORD 11 (Pfad einer Datei) TRUENAME Datei | SETWORD (Datei mit komplettem Pfad) Und was passiert, wenn SETWORD keine Eingabe per PIPE erhält? Dann wird die Eingabe halt von der Tastatur eingelesen, z.B.: SETWORD > TMP.BAT call TMP.BAT INPUT Verzeichnis der TMP.BAT ----------------------- In den Beispielen wurde die TMP.BAT im aktuellen Verzeichnis angelegt, und sollte daher anschließend wieder gelöscht werden. Das kann man sich sparen, wenn immer das Verzeichnis %TEMP% verwendet wird, z.B.: CD | SETWORD > %temp%\TMP.BAT call %temp%\TMP UDIR Zum Programm SETWORD -------------------- Als Trennzeichen zwischen Wörtern in der Eingabedatei gelten Leerzeichen, Komma, Semikolon, Gleichheitszeichen und CR,LF (Zeilenabschluß). Max. Größe der Datei: 60 KB. Weitere Anwendungen ------------------- DIR liefert eine Menge Informationen. Neben dem aktuellen Laufwerk kann für jede beliebige Datei z.B. der Verzeichnispfad, der Name ohne Extension, nur Extension, Datei-Datum und -Größe ermittelt werden. Bei Bedarf läßt sich auch eine bestimmte Zeile per FIND herausziehen (hier um die Anzahl Dateien zu ermitteln): DIR *.GIF | FIND "Datei(en)" | SETWORD 1 Bei DATE und TIME hält DOS an und wartet auf eine Eingabe oder RETURN. Dieses RETURN wird daher per ECHO an DATE/TIME gepiped: ECHO.| DATE | SETWORD 4 DOS-Version ----------- Die Beispiele oben gelten für MS-DOS 5.0 (deutsch). Abweichungen im Output bei anderen Versionen möglich, also bitte ausprobieren und abzählen... Und hier ist das Proggi: --------------------------------------------schnipp--------------- e100 BE 81 0 AC "< t"FB "N+"C0 "*"FF B9 A 0 8A 1C "F"80 EB "08"CB e118 "s"6 F7 E1 1 D8 "s"ED "P"BE A2 1 "+"DB 89 F2 B9 0 F0 B4 "?"CD e12E "!"8B D8 C6 0 1A B9 7 0 BA 9B 1 BB 1 0 B4 40 CD "!]"85 ED "u" e145 1 "E+"C9 AC "< t"FB "<,t"F7 "<;t"F3 "<=t"EF "<"D "t"EB "<"A e160 "t"E7 "N"89 F2 80 "<"1A "t F"8A 4 "< t"14 "<,t"10 "<;t"C "<=" e17B "t"8 "<"D "t"4 "<"A "u"E0 "A;"CD "u"BF 8B CE ")"D1 B4 40 CD e191 "!"B4 ">"CD "!"B8 0 "L"CD "!set %1=" n SETWORD.COM rCX A2 w q --------------------------------------------schnapp--------------- Das Skript enthält den kompletten Programm-Code als Folge von Eingabebefehlen für DEBUG, und am Ende die Anweisungen zum Schreiben der Datei. Zur Erstellung der COM-Datei bitte wie folgt vorgehen: * Skript zwischen den Trennlinien ausschneiden und in eine Datei kopieren, z.B. SETWORD.SCR * Auf der Befehlsebene eingeben: DEBUG < SETWORD.SCR Die Eingabe-Datei wird damit von DEBUG als Input abgearbeitet, und das Resultat wird in die Datei SETWORD.COM (ins aktuelle Verzeichnis) geschrieben. Das war's ====================================================================