Feine DOS-Fähigkeiten


Im vorletzten Kapitel wurde in die grundlegenden Funktionen von DOS eingeführt: Sich im Verzeichnisbaum bewegen, Dateien erzeugen, kopieren, löschen. Nichts, was man nicht mit einem Dateimanager wie dem Windows-Explorer auch könnte.

In diesem Kapitel kommen nun DOS-Fähigkeiten zur Sprache, die schon näher ans Programmieren heranführen. Und die in Verbindung mit einer Programmiersprache ganz erstaunliche Dinge ermöglichen. Das Prinzip dieser "erstaunlichen Dinge" sei schon vorweggenommen: Wir können später von unseren selbst geschriebenen Programmen aus DOS-Kommandos absetzen. Und damit all die DOS-Funktionen in unseren Programmen nutzen, die wir schon kennengelernt haben und noch kennenlernen werden. Und das ist der wesentliche Unterschied zu ihrem Dateimanager: Den können Sie aus einem eigenen Programm heraus nicht benutzen und automatisieren (jedenfalls nicht so ohne weiteres.)

Wildcards

Suffixe

Ein Dateiname bestand unter DOS immer aus bis zu acht Buchstaben Name und 3 Buchstaben Suffix. Also z.B. "command.com" oder "meintext.txt". Diese Regelung wurde durch DOS von seinem Vorläufer CP/M übernommen. Die 8-Buchstaben- Grenze ist längst gestrichen. Heute kann man Dateinamen mit über 200 Buchstaben generieren - wem das Spass macht. Aber die Suffixe werden weiterhin beibehalten. Sie sind sogar elementar geworden. Denn anhand ihnen wird identifiziert, um was für einen Dateityp es sich handelt und mit welchem Programm man ihn bearbeiten kann. Ein paar bekannte Suffixe und die in der Regel zuständigen Programme sind:

Suffix Zuständiges Programm
doc Microsoft Word
xls Microsoft Excel
pdf Acrobat Reader-Datei
html WWW-Browser
txt Editor
gif Bildbetrachter
jpg Bildbetrachter
mp3 MP3-Player (Musikprogramm)
mpeg Video-Player
avi Video-Player
bas Basic-Interpreter

u.v.m.

Auswahl von Suffixen

Suffixe machen es also theoretisch möglich, alle Dateien eines Typs auf einmal zu behandeln oder auszuwählen. Man muss nur alle Dateien mit einem bestimmten Suffix ansprechen. Geht das aber auch praktisch? Klar doch.

DOS beherrscht s.g. "Wildcards". Das sind Symbole im Dateinamen. Entweder ein ? oder ein *. Wesentlich wichtiger als das ? ist *. Er steht für einen beliebigen String. Das heisst, es werden durch diesen Namen alle Dateien bezeichnet, deren Name mit den angegeben Buchstaben übereinstimmt, aber an der Stelle des * irgendetwas stehen haben.

Ein Beispiel sagt hier mehr als tausend Worte: "n*t" steht für alle Namen, die mit n beginnen und mit t enden, also "nagt", "näht", "numeriert", "ndjskdjht", "n182kt".

"*.txt" steht für alle Namen, die mit ".txt" enden, also "a.txt", "meintext.txt", "hallo.txt" usw.

"hallo*.*" steht für alle Namen, die mit "hallo" beginnen, also "hallo1.txt", "hallodies.bas", "hallohallo.doc".

Das ? hingegen steht für genau einen beliebigen Buchstaben. "hallo.???" z.B. meint "hallo.txt", "hallo.doc", aber nicht "hallo.html".

Anwendung

Vielen DOS-Befehlen kann man oder muss man Dateinamen beifügen. Durch Verwendung von Wildcards kann man nun ganz flexibel ganze Dateigruppen mit einem Schlag behandeln. Ein paar Beispiele

dir *.txt Zeige alle Textdateien
dir /s *.txt Zeige alle Textdateien in diesem Verzeichnis und allen Unterverzeichnissen.
type *.htm Zeige den Inhalt aller HTML-Dateien auf dem Bildschirm an.
xcopy /s *.bas A: Kopiere alle Basic-Programme aus dem aktuellen Verzeichnis und allen Unterverzeichnissen (Option /s) auf eine Diskette
xcopy /s *.* A: Kopiere ALLE Dateien aus dem aktuellen Verzeichnis und allen Unterverzeichnissen (Option /s) auf eine Diskette
xcopy /s /d:01-01-2003 *.* A: Kopiere alle Dateien, die seit dem 01.01.2003 verändert oder erstellt wurden, aus dem aktuellen Verzeichnis und allen Unterverzeichnissen (Option /s) auf eine Diskette
ren a*.jpeg a*.jpg Benenne alle Bilder, die mit a anfangen und die Endung .jpeg tragen, in .jpg um.

Wildcards für beliebige Befehle

Wildcards sind zunächst keine Eigenschaft von DOS, sondern lediglich eine Konvention unter DOS. Die Interpretation der Wildcards muss das entsprechende Programm selbst übernehmen (ganz im Gegensatz zu Unix, das Wildcards für das entsprechende Programm in explizite Dateinamen übersetzt).

Das heisst: Ausser dir, copy, xcopy und hier und da ein paar Programmen können wir keine Wildcards verwenden. Denken wir. Es gibt jedoch einen Befehl, der das ermöglicht: Eine FOR-Schleife.

Syntax: for %1 in () do %1. Das sieht wilder aus, als es ist. Das "%1" ist einfach ein formaler Platzhalter für die Datei, damit hinten DOS weiss, an welcher Stelle der Befehl den Dateinamen haben möchte. Für können wir irgendeinen Wildcardnamen einsetzen, z.B. *.* oder *.txt oder a*.*. kann irgendein DOS-Executable sein. Und %1 setzen wir an die Stelle, an der der Befehl den Dateinamen haben möchte. Anwendungsbeispiel: Der Befehl grep sucht in einer Textdatei nach einem String. z.B. "grep "Hallo!" a.txt" sucht in a.txt nach dem String "Hallo!". Nun setzen wir das in Verbindung mit FOR ein: for %1 in (*.txt) do grep "Hallo!" %1. Dies durchsucht alle Dateien mit der Endung .txt nach Strings "Hallo!" und printet die Fundstellen auf den Bildschirm.

Noch eine kleine lustige Anekdote zu Wildcards, die sich während meiner Diplomarbeitszeit ereignet hat. Das Betriebssystem, auf dem alle arbeiteten, war UNIX. Da aber viele Dinge bei DOS von UNIX abgeschaut sind, (auch die Pipes im folgenden Abschnitt), verwundert es nicht, dass die Wildcards bei UNIX fast genau gleich funktionieren. Nur gibt es dort noch mehr und man kann noch viel kompliziertere Dinge mit ihnen tun. Und: Suffixe gibt es unter Unix nicht zwingend. Wenn man unter DOS alle Dateien ansprechen möchte, muss man "*.*" formulieren, unter UNIX nur "*". Der del-Befehl heisst unter Unix übrigens "rm".

Eines Tages kam ein Mitarbeiter sehr zerknirscht zum System-Administrator und fragte ihn: "Du, wann ist denn das letzte Backup gemacht worden?". Alle horchten auf. Was war passiert? Der Mitarbeiter war für eine Stunde von seiner Workstation weggegangen. Als er wiederkam, befand sich eine Datei namens "*" in seinem Verzeichnis. Das störte ihn. Also löschte er sie: "rm *". Den Rest können Sie sich denken...

Umleitungen und Pipes

Für DOS ist alles eine Datei. Nicht nur die Datei auf dem Datenträger, sondern auch der Bildschirm und die Tastatur. Schreibt ein Programm auf den Bildschirm, so schreibt es in Wirklichkeit in eine Datei, die laufend auf dem Bildschirm angezeigt wird. Diese nennt man die "Standardausgabe". Entsprechend gibt es auch die "Standardeingabe", die Datei, aus der ein Programm die Tastatureingaben liest.

Der Vorteil dieses Prinzips ist, dass man diese Datei ändern kann. Die Standardeingabe muss nicht zwingend mit der Tastatur verbunden sein. Sondern man kann DOS auch anweisen, ein Programm so auszführen, dass die Standardeingabe eine Datei ist. Das Programm nimmt also an, es bekäme seine Eingaben über die Tastatur, in Wirklichkeit kommen sie aber aus einer Textdatei. Das ist sehr praktisch. Fragt ein Programm z.B. über die Tastatur eine Menge Informationen ab, so kann ich diese auch einfach mit einem Editor in eine Datei schreiben und dem Programm diese Datei "vor die Nase setzen".

Und wie geht das? <Befehl> > <file> leitet die Standardausgabe auf <file> um. Schreibt <Befehl> also auf den Bildschirm (und das tun die meisten Befehle), dann geht die Ausgabe jetzt in die Datei <file>. "dir > a.lst" schreibt z.B. die Verzeichnisinformationen in die Datei a.lst. Sehr viel mehr sinnvolle Anwendungen der Dateiumleitung mit den elementaren DOS-Befehlen finde ich gerade nicht, aber diese ist sehr praktisch. Praktisch sind auch Dateiumleitungen mit selbst geschriebenen Programmen - dazu später mehr.

Das Zeichen für die Umleitung der Dateieingabe ist übrigens <

Wir können das for-Schleifen-Beispiel von oben noch durch eine Umleitung ergänzen, da es praktisch wäre, das Ergebnis der Stringssuche in einer Datei zu haben, wo man hin- und herblättern kann. Das geht ganz einfach: for %1 in (*.txt) do grep "Hallo!" a.txt > a.lst. Anschliessend sind die Fundstellen in a.txt aufgelistet.

Dann gibt es noch die Pipes. Man kann eine ganze Folge von DOS-Befehlen miteinander verketten, indem man die Standardausgabe des ersten Befehls zur Standardeingabe des nächsten macht. Das nennt man "Piping". ("Pipes" sind auf deutsch "Röhren", hier ist insbesondere die Rohrpost gemeint.) Das einzige Piping, das ich bisher verwendet habe, ist "type <file> | more". "more" ist ein Programm, das von der Standardeingabe liest und das Ergebnis gleich wieder auf dem Bildschirm anzeigt - wenn der Bildschirm voll ist, wartet es auf einen Tastendruck. Auf diese Art und Weise kann man den type-Befehl dazu einsetzen, eine lange Textdatei bildschirmseitenweise auszugeben. Soweit ich weiss, funktioniert das Piping auch nicht so gut unter Windows, da es eigentlich den synchronen Betrieb zweier Programme und das Lesen einer gemeinsamen Datei erfordert, was zumindest unter DOS eigentlich nicht ging.

Batch-Dateien

Nehmen wir an, wir wollen jeden Tag ein Backup unserer Programmierarbeit von Festplatte auf Diskette machen. Wir arbeiten mit fünf Dateien, die myprog?.bas, descr1?.txt, dat1?.dat, mytab?.dat und toolut?.bas heissen sollen. Das ? steht jeweils für eine Ziffer, die die Version angibt. Es soll jeweils nur die neueste Version gesichert werden. Noch dazu sollen die verschiedenen Dateien in verschiedene Verzeichnisse auf der Diskette: Daten sollen nach A:\data und Programme nach A:\prog. Was tun? Jedesmal fünf copy-Befehle auf DOS-Ebene eingeben? Oder fünfmal Dateien im Explorer packen und in das jeweilige Verzeichnis ziehen? Das muss nicht sein!

Die Lösung ist auch ganz einfach: Wir schreiben die fünf Copy-Befehle in eine Textdatei und speichern sie ab. Dann haben wir ein "DOS-Programm". Und das geht tatsächlich. Nennen wir die Datei nämlich mit der Endung .bat, können wir sie wie einen eigenen DOS-Befehl verwenden. Man nennt das einen Skript.

Wir schreiben also mit dem Editor in eine neue Datei

copy C:\prog\myprog7.bas A:\prog
copy C:\prog\ toolut7.bas A:\prog
copy C:\prog\dat17.dat A:\data
copy C:\prog\descr17.txt A:\data
copy C:\prog\mytab1.dat A:\data

...und speichern sie als "backup.bat" ab. Anschliessend müssen wir nur noch backup als DOS-Befehl eingeben und die Copy-Befehle werden hintereinander ausgeführt.

Die Skriptsprache von DOS

...ist leider ziemlich primitiv und mit BASIC nicht zu vergleichen. Daher gibt es inzwischen eine ganze Reihe von (meist kostenlosen) Skriptinterpretern - bis hin zum mächtigen Perl - die mehr können. Für den Anfang wird uns jedoch die Standard-DOS-Skriptsprache genügen. Vor allem, wenn wir sie in Verbindung mit BASIC und anderen Programmiersprachen einsetzen können.

Im folgenden also die Sprachelemente

echo
...gibt einfach eine Meldung aus.
Beispiel: echo Hallo! Das ist ein Skript! Keine Anführungszeichen um den Ausgabestring! Standardmässig gibt DOS ohnehin jeden Skiptbefehl auf den Bildschirm aus. Wenn man das nicht wünscht, muss man als ersten Befehl @echo off in den Skript schreiben.
pause
...hält einen Skript an und fordert zu einer Tasteneingabe auf. Kein Argument.
%1, %2, %3 ...
...sind Variablen, die man im Skript verwenden kann. Initialisiert werden die Variablen auf der Kommandozeile. Lautet unser Skript copy %1 A:\ und nennen wir ihn copytodisk.bat, dann führt der Aufruf von "copytodisk myprog.bas" dazu, dass im Skript "myprog.bas" als %1 verwendet und daher nach A: kopiert wird. %1 ist immer der erste übergebene Parameter, %2 der zweite usw.
goto
...Funktioniert wie bei BASIC. Fast. In Skripten gibt es keine Zeilennummern. Sondern man benutzt s.g. LABELS. Das ist einfach ein Text, der eine bestimmte Stelle im Programm markiert. In DOS-Skripten werden die Labels mit einem Doppelpunkt eingeleitet:
echo Das ist ein Skript
echo Dieser Teil wird ausgeführt
goto ende
echo Dieser Teil wird nie ausgeführt
:ende
echo Hier ist das Ende und das wird
echo ausgeführt
If exist
Der If-Befehl in DOS ist sehr spezialisiert. Die erste Variante lautet: If [not] exist Befehl Das Not in Klammer bedeutet: Man kann vor das "exist" noch ein "not" setzen. Das Ganze funktioniert ohne NOT so: Wenn DOS findet, wird der Befehl ausgeführt, ansonsten nicht. Mit NOT: Wenn DOS die Datei NICHT findet, wird der Befehl ausgeführt. Beispiel: if exist %1 copy %1 A: kopiert das erste Argument nach A:, falls es existiert. Ein bisschen komplizierter:
IF exist %1 GOTO docopy
echo Datei existiert nicht!
GOTO ende
:docopy
copy %1 A:
:ende
If string1==string2
Hier werden zwei Strings verglichen. Wichtig, um Optionen zu verarbeiten. Beispiel:
copy %1.bas A:
if %2==1 copy %1.dat A:
Der Skript heisse backup.bat. Hier kann ich nun auf der Kommandozeile angeben: "backup myprog 0". Dann wird nur myprog.bas nach A. kopiert. Oder ich gebe "backup myprog 1" an. Dann wird auch myprog.dat nach A: kopiert.
if errorlevel
Mit dieser Variante kann man mit (selbstgeschriebenen) Programmen kommunizieren. Wir müssen uns das so vorstellen, dass unser BASIC-Programm mit einem END-Befehl endet. Der END-Befehl erhält jedoch ein Argument, eine einfache Zahl. Also z.B. END(1). Diese Zahl wird nach Ende des Programms DOS übergeben und stellt den ERRORLEVEL da. Der Skript kann unmittelbar nach Aufruf des Programms mit IF ERRORLEVEL darauf reagieren. Er folgt dem IF, wenn der zurückgegebene Code des Programms grösser oder gleich dem angegebenen Wert ist. Ein Beispiel:
test 
IF errorlevel 1 GOTO docopy
GOTO ende
:dopcopy
copy %1 A:
:ende
Zuerst wird das Programm "test" ausgeführt. Dieses gibt einen Code zurück. Ist dieser Code >=1, dann wird kopiert. Ansonsten wird der docopy-Teil übersprungen.
For-Schleifen
Sie haben wir schon bei den Wildcards kennengelernt. In Skripten können wir sie natürlich auch verwenden. Dabei gibt's zwei Besonderheiten zu beachten. Erstens muss beim Platzhalter ein Doppelprozent stehen, also for %%1 in () do %%1. Ansonsten interpretiert der Skript %1 als Übergabeparameter und meldet einen Syntaxfehler. Das %% veranlasst DOS, ein echtes Prozentzeichen zu lesen.
Die zweite Besonderheit ist, dass man dem Platzhalter nicht nur Dateien, sondern auch einfache Zahlen übergeben darf. Man kann also eine Schleife einfach fünfmal durchlaufen, indem man schreibt: for /l %%i in (1,1,5) do .... In der Klammer steht (Anfang, Schritt, Ende). Für diese letzte Option müssen Sie allerdings DOS mit dem Befehl "cmd /x" starten und es funktioniert nur auf WinNT/2000/XP.