Im ersten Teil haben wir die Ausgabe von ver mit > in eine Datei geschickt und sie aus VFP gelesen. Hier kommt, was dahintersteckt: wo ein Konsolenprogramm schreibt und liest, wie man jedes davon umleitet und wie ein Programm dem, der es gestartet hat, sagt, ob es gut gelaufen ist. Damit können Sie Programme verketten und in einer .bat benutzen, ohne auf den Bildschirm zu schauen.

Drei Kanäle

Jedes Konsolenprogramm startet mit drei offenen Kanälen:

KanalNameWofür
Eingabestdinwas das Programm liest (die Tastatur, wenn Sie nichts anderes sagen)
Ausgabestdoutdas Ergebnis
FehlerstderrWarnungen und Fehler

Ausgabe und Fehler landen auf demselben Bildschirm, also sieht man auf den ersten Blick keinen Unterschied. Es sind zwei verschiedene Kanäle, und man kann sie an verschiedene Orte schicken.

VFP hat etwas Ähnliches für die Ausgabe. Was Sie mit ? schreiben, geht auf den Bildschirm, und mit SET ALTERNATE schicken Sie es zusätzlich in eine Datei:

Die Ausgabe von ? in eine Datei, wie das > der Konsole
SET ALTERNATE TO echo.txt
SET ALTERNATE ON
? "Offene Rechnungen:", 12
SET ALTERNATE OFF
SET ALTERNATE TO

In echo.txt steht dann Offene Rechnungen: 12. Was VFP nicht hat, ist ein eigener Kanal für Fehler: Ein VFP-Fehler öffnet ein Fenster oder springt in Ihr ON ERROR.

Die Ausgabe in eine Datei

> schickt die Ausgabe in eine Datei statt auf den Bildschirm. Gibt es die Datei schon, wird sie ersetzt:

ping -n 1 127.0.0.1 > ausgabe.txt

Auf dem Bildschirm erscheint nichts, und ausgabe.txt enthält die 9 Zeilen, die Sie gesehen hätten. Mit >> wird angehängt statt ersetzt: noch ein ping -n 1 127.0.0.1 >> ausgabe.txt, und die Datei hat 18 Zeilen.

Wenn Sie die Ausgabe nicht interessiert, schicken Sie sie nach nul, einer besonderen Windows-Datei, die alles verschluckt:

ping -n 1 127.0.0.1 > nul

Fehler gehen einen anderen Weg

Schicken Sie einmal die Ausgabe eines Git-Unterbefehls, den es nicht gibt, in eine Datei:

git estado > ergebnis.txt
git: 'estado' is not a git command. See 'git --help'.

Die Meldung erscheint trotzdem auf dem Bildschirm, und ergebnis.txt bleibt leer, 0 Bytes. Git hat die Meldung über den Fehlerkanal geschrieben, und > leitet nur die Ausgabe um. Für den Fehler setzt man eine 2 davor:

git estado 2> fehler.txt

Jetzt bleibt der Bildschirm leer, und die Meldung steht in fehler.txt. Wollen Sie beides in derselben Datei, schickt 2>&1 den Fehler dorthin, wohin die Ausgabe geht:

git estado > alles.txt 2>&1

Dafür sind zwei Kanäle gut: Sie speichern das Ergebnis in einer Datei, und Probleme erscheinen weiter auf dem Bildschirm oder in einer anderen Datei, ohne sich mit den Daten zu vermischen. Schreibt ein Programm JSON auf die Ausgabe und seine Warnungen auf den Fehlerkanal, kommt das JSON sauber heraus.

Nicht jedes Programm hält sich daran. ping schreibt seine eigenen Fehler auf die normale Ausgabe: ping -n 127.0.0.1 > p.txt zeigt nichts, und die Fehlermeldung (bei mir „Debe especificar la dirección IP.“) landet in p.txt. Wenn ein Fehler nicht dort auftaucht, wo Sie ihn erwarten, sehen Sie auch in der Ausgabedatei nach.

Die Eingabe aus einer Datei

< macht das Gegenteil von >: Das Programm liest aus einer Datei statt von der Tastatur. sort sortiert die Zeilen, die über die Eingabe ankommen:

sort < staedte.txt
Almeria
Madrid
Zaragoza

Tippen Sie sort allein, wartet es darauf, dass Sie Zeilen eingeben, weil seine Eingabe die Tastatur ist. Viele Konsolenprogramme arbeiten so: Sie lesen ihre Eingabe, verarbeiten sie und schreiben das Ergebnis.

Die Pipe: die Ausgabe des einen in die Eingabe des anderen

Der senkrechte Strich | verbindet zwei Programme: Was das erste auf seine Ausgabe schreibt, kommt beim zweiten über die Eingabe an, ohne Umweg über eine Datei. tasklist listet die laufenden Prozesse auf, und find behält die Zeilen, die einen Text enthalten. Mit geöffnetem VFP:

tasklist | find /i "vfp9.exe"
vfp9.exe                      6808 Console                    1    30.176 KB

Noch eine: find /c /v "" zählt die Zeilen, die ankommen. Hinter ein dir /b gesetzt, zählt es, was in einem Ordner liegt:

dir /b C:\Windows | find /c /v ""
102

Keines der beiden Programme weiß, dass es das andere gibt. Jedes macht seinen Teil, und die Pipe verbindet sie. So arbeitet die Konsole: viele kleine Programme, die man kombiniert.

Der Exit-Code

Wenn ein Konsolenprogramm endet, gibt es dem, der es gestartet hat, eine Zahl zurück. Das ist der Exit-Code, und die Regel ist einfach: 0 heißt, es ist gut gelaufen, jede andere Zahl heißt, nicht. Was jede Zahl ungleich 0 bedeutet, entscheidet jedes Programm selbst.

In cmd steht der letzte Code in %ERRORLEVEL%:

ping -n 1 127.0.0.1 > nul
echo %ERRORLEVEL%

Das sind die Codes der Befehle, die wir im Kurs benutzt haben:

BefehlCode
ping -n 1 127.0.0.1 (antwortet)0
ping -n 1 -w 500 192.0.2.1 (niemand antwortet)1
git estado (Unterbefehl, den es nicht gibt)1
git log --onelin (falsch geschriebene Option)128

Mit dem Code entscheidet ein Skript, was es tut, ohne zu lesen, was das Programm geschrieben hat. && führt das Folgende nur aus, wenn der Code 0 war, und || nur, wenn nicht:

tasklist | find /i "vfp9.exe" > nul && echo VFP offen || echo VFP geschlossen

find gibt 0 zurück, wenn es den Text gefunden hat, und 1, wenn nicht. Also sagt diese Zeile, ob irgendein VFP läuft. Mit geöffnetem VFP antwortet sie „VFP offen“, geschlossen „VFP geschlossen“.

In PowerShell steht der Code in $LASTEXITCODE statt in %ERRORLEVEL%.

Der Exit-Code eines VFP-Programms

Es ist dieselbe Idee wie das RETURN einer Prozedur, nur zwischen Programmen: Das endende Programm hinterlässt dem startenden eine Zahl. Eine VFP-.exe, die mit QUIT endet, beendet sich immer mit 0, wie auch immer es gelaufen ist. QUIT nimmt keinen Code an. Für eine andere Zahl muss man Windows fragen:

Ein VFP-Programm mit Exit-Code 3 beenden
DECLARE ExitProcess IN kernel32 INTEGER nCode
ExitProcess(3)

Ich habe es ausprobiert, indem ich VFP mit einem Programm gestartet habe, das nur das tut: Es endet mit 3, und das daneben, das QUIT macht, mit 0. ExitProcess beendet den Prozess sofort, ohne das normale Herunterfahren von VFP. Rufen Sie es also erst auf, wenn Ihre Tabellen geschlossen und alles gespeichert ist.

Damit können eine .bat oder die Aufgabenplanung wissen, ob Ihr nächtlicher Lauf gut gegangen ist.

Umlaute, die verändert ankommen

Im ersten Teil kam beim Lesen der Ausgabe von ver aus VFP Versi¢n heraus. Das liegt daran, dass die Konsole, die RUN öffnet, mit der Codepage 850 aus MS-DOS schreibt, und VFP mit der 1252 von Windows arbeitet. chcp sagt Ihnen, welche die Konsole benutzt (bei mir auf Spanisch):

Página de códigos activa: 850

Buchstaben mit Akzent oder Umlaut haben in beiden verschiedene Nummern. CPCONVERT überträgt den Text von einer Codepage in die andere:

Die Ausgabe eines Konsolenprogramms aus VFP lesen, mit Umlauten
RUN ver > version.txt
? CPCONVERT(850, 1252, FILETOSTR("version.txt"))

Und jetzt steht da Microsoft Windows [Versión 10.0.26200.9457]. Ein deutsches Windows benutzt in der Konsole ebenfalls die 850; wenn chcp bei Ihnen eine andere Zahl meldet, setzen Sie diese ein.

Wenn Sie PowerShell benutzen

Die Umleitungen sind dieselben, mit zwei Unterschieden, die beim Lesen aus VFP Ärger machen:

  • > schreibt UTF-16. In der PowerShell 5.1, die mit Windows kommt, hinterlässt ping -n 1 127.0.0.1 > ps.txt eine Datei, die mit den Bytes FF FE beginnt und zwischen jedem Buchstaben ein Null-Byte hat: Sie ist doppelt so groß wie dieselbe Datei aus cmd. Liest man sie mit FILETOSTR so, wie sie ist, kommt jeder Buchstabe mit einem CHR(0) dahinter. STRCONV macht normalen Text daraus, wenn man vorher die ersten zwei Bytes weglässt: STRCONV(SUBSTR(FILETOSTR("ps.txt"), 3), 6).
  • nul schreibt sich $null. git estado 2> nul schlägt in PowerShell fehl; was funktioniert, ist git estado 2> $null.

Zum Üben

In einem cmd, in Ihrem Testordner:

ping -n 1 127.0.0.1 > ausgabe.txt
ping -n 1 127.0.0.1 >> ausgabe.txt
type ausgabe.txt
git estado > ergebnis.txt
git estado 2> fehler.txt
type fehler.txt
dir /b C:\Windows | find /c /v ""
ping -n 1 -w 500 192.0.2.1 > nul && echo Antwortet || echo Keine Antwort

Und im Befehlsfenster von VFP:

Die Ausgabe von dir, aus VFP gelesen, mit Umlauten
RUN dir C:\Windows > ordner.txt
? CPCONVERT(850, 1252, FILETOSTR("ordner.txt"))

In Teil 4: wie man die Hilfe eines Konsolenprogramms liest, und was in der Hilfe eines eigenen Programms stehen sollte.