BATch-Dateien - kleine Tipps

An dieser Stelle finden Sie eine Sammlung von kleinen Codeschnipseln für scheinbar triviale Sachen. Vielleicht ist es aber für den ein oder anderen bei einem Problem hilfreich...

alle anzeigen

Wiederholung der Kommandos unterdrücken
Ausgabe des Kommandos unterdrücken
Ausgabe von Fehlermeldungen unterdrücken
Test - existiert eine Datei?
Test - existiert ein Verzeichnis?
bei Fehlschlägen [n] mal wiederholen
aus der Registry lesen
in die Registry schreiben
Debuggen von BAT-Dateien
Laufwerke verbinden/ trennen
Ausführung nur einmal am Tag gestatten
Austauschen von Textinhalten
net send: an mehrere Benutzer dieselbe Nachricht senden
Pause einlegen
Benutzereingabe in einer Variable speichern
Ausgabe in mehreren Sprachen (Win XP)
Dateinamen/ Zeichenketten zerlegen (Win XP)
Ausgabe eines Befehls in eine Variable holen (Win2k)
HTML-Ausgabe erzeugen
eine Textdatei parsen
eine zufällige Datei wählen
Bei Erreichen einer Dateigrösse etwas ausführen

Wiederholung der Kommandos unterdrücken

Dagegen hilft zum einen ein vorangestelltes @-Zeichen.
copy datei1.txt datei2.txt
... zeigt in der Ausgabe den Prompt (meist mit dem aktuellen Pfad) und das Kommando an.
C:\TEMP\>copy datei1.txt datei2.txt
            1 Datei(en) kopiert
Mit einem
@copy datei1.txt datei2.txt
... verschwindet der Prompt.

Damit man nicht vor jedes Kommando ein @ setzen muss, dann man dies auch generell unterdrücken lassen:
@echo off
.. schaltet es aus und ein
echo on
... wieder ein.

Tipp
Mit Hilfe eines gezielten echo on lässt sich eine noch fehlerhafte Batch-Datei einfacher debuggen.

Befehle: copyecho

Seitenanfang


Ausgabe des Kommandos unterdrücken

Hit Hilfe der Ausgabeumlenkung ">" kann man die Ausgabe, die auf der Konsole erscheint, z.B. in eine Datei umleiten. Eine vorhandene Datei wird bei einem einfachen ">" überschrieben. Bei Verwendung eines doppelten ">>" wird die Ausgabe an die angegebene Datei angehängt.
Es gibt zudem ein spezielles Gerät namens "nul" (es entspricht dem /dev/null unter UNIX), das als Müllschlucker dient. Alles was man hierher sendet, wird nicht in einer Datei angelegt, sondern ins Nirvana geschickt.

Beispiel:
Das Kommando "pause" liefert eine Standardmeldung, die zum Drücken einer Taste auffordert. Dieser Text ist bei einer engl. Windows-Version ebenfalls englisch (ist ja klar).
Um diese Ausgabe durch eine eigene Meldung zu ersetzen, die dem Benutzer z.B. vielleicht einen genaueren Status anzeigt, zeigt man den gewünschten Text mit echo an. Die Ausgabe des Kommandos pause wird umgeleitet:

echo weiter mit beliebiger Taste oder [Strg]+[C] zum abbrechen.
    pause >nul

Befehle: echopause

Seitenanfang


Ausgabe von Fehlermeldungen unterdrücken

Mit Hilfe der einfachen Ausgabeumleitung mit Hilfe des >-Zeichens hinter einem Kommando, wird die produzierte Ausgabe des aufgerufenen Kommandos unterdrückt. Tritt ein Fehler auf, sieht man die Fehlermeldung trotzdem am Bildschirm. Ursache ist, dass es neben dem "Standardausgabekanal" auch einen "Fehlerkanal" gibt. Um Fehlermeldungen ebenfalls zu unterdrücken, gibt man vor dem Umleitungszeichen eine 2 (die Nummer des umzuleitenden Kanals) an:

Beispiel:
mkdir %temp%\workdir 2>nul
... erzeugt das Verzeichnis "workdir" im TEMP-Ordner. Sofern es bereits existieren sollte, erscheint die Fehlermeldung "Verzeichnis existiert bereits" nicht.

Befehle: mkdir

Seitenanfang


Test - existiert eine Datei?

Schlüssel zum Erfolg ist das Kommando "exist" - meist ist es mit einer if-Klausel anzutrefen:
if exist [Dateiname] [auszuführendes Kommando, wenn Datei existiert]

Beispiel:
Anbei eine Bat-Datei, die prüft, ob der erste übergebene Parameter eine existierende Datei ist:

@echo off
     
    if exist %1 goto TUWAS
    echo ERROR: Datei "%1" nicht gefunden!
    goto ENDE
     
    :TUWAS
    echo Jepp - die Datei "%1" existiert... - ich zeige sie mal an:
    type "%1"
     
    :ENDE
    
Bat-Beispiel


Befehle: echoifgototype

Seitenanfang


Test - existiert ein Verzeichnis?

Wiederum kann man dies mit "exist" prüfen. Genaugenommen prüft exist das Vorhandensein von einer Datei oder aber einem Verzeichnis. Um abzusichern, dass es sich um ein Verzeichnis und eben nicht um eine Datei handelt, kann man auf das Gerät nul zurückgreifen. Dieses befindet sich scheinbar in jedem Verzeichnis:
if exist [Verzeichnis]/nul [auszuführendes Kommando, wenn Datei existiert]

Beispiel:
Anbei eine Bat-Datei, die prüft, ob der erste übergebene Parameter ein existierendes Verzeichnis ist:

@echo off
     
    if exist %1/nul goto TUWAS
    echo ERROR: Verzeichnis "%1" nicht gefunden!
    goto ENDE
     
    :TUWAS
    echo Jepp - das Verzeichnis "%1" existiert... - ich liste es auf:
    dir "%1"
     
    :ENDE
    
Bat-Beispiel


Eine andere Möglichkeit wäre der Aufruf des dir-Kommandos, wo man mit Hilfe des Parameters /a die gewünschten File-Attribute angibt.
dir /a:d "%1" >nul

Befehle: direchoifgoto

Seitenanfang


bei Fehlschlägen [n] mal wiederholen

Manchmal möchte man eine fehlgeschlagene Aktion in der BAT-Datei wiederholen. Das Problem dürfte sein: Wie zähle ich die Anzahl der Versuche? Eine typorientierte integer Variable, die man hochzählen kann, gibt es bei BAT-Dateien nicht...
Man kann sich aber mit Stringvergleichen behelfen. Man definiert eine Variable für den Counter und eine weitere für die Anzahl Maximum der Versuche. Bei jedem Durchlauf wird der Counter um ein (bestimmtes) Zeichen erweitert. Es wird beendet, wenn der Counter meinem Maximum entspricht.
Anbei eine Demo-BAT-Datei, die das verdeutlichen soll:

@echo off
    rem --- Variablen setzen ---
    set counter=
    set maxcount=xxxxx
     
    rem --- MAIN ---
    :RUNHERE
    echo --- Ich tu hier was...
    :: Hier muesste eine Aktion und eine Verzweigung
    :: fuer den erfolgreichen Durchlauf hinein...
    :: if %ERRORLEVEL%==0 goto ENDE
     
    set counter=%counter%x
    if "%counter%"=="%maxcount%" goto ERRMAX
    echo %counter%
    echo ich warte kurz ...
    ping -n 5 localhost >nul
    goto RUNHERE
     
    :ERRMAX
    echo SORRY - max. Anzahl der Versuche wurde erreicht.
    goto ENDE
     
    rem --- EXIT ---
    :ENDE
    pause
    
Bat-Beispiel


Bei neueren Windows-Versionen kann man mit Zahlenwerten rechnen und einen Counter erhöhen - die "Krücke" mit dem String braucht man nicht. Man verwende einfach
set /a [Variable]=[Zuweisung]

    set counter=0
    set maxcount=5
    (...)
    set /a counter=%counter% + 1
    if "%counter%" EQU "%maxcount%" goto ERRMAX
    (...)
    
Bat-Beispiel


Befehle: echogotoifpingremset

Seitenanfang


aus der Registry lesen

Die schlechte Nachricht vorweg: direkt auf die Registry kann man (natürlich) nicht zugreifen. Aber man kann sich behelfen.
Unser Helfer heisst diesmal regedit. Dieses ist nicht nur ein Programm, sondern es sind 2 Programme in einer EXE-Datei (ein sog. DOS-Stub und Windows-Stub). Wenn der Befehl regedit ohne Parameter unter Windows aufgerufen wird, bekommen Sie die grafische Oberfläche des sicher bekannten Registry-Editors zu sehen. Befinden Sie sich im DOS-Modus oder aber setzen Sie einen Parameter dahinter, startet das Konsolenprogramm.
Um aus der Registry zu lesen, muss man den gewünschten gewünschten Schlüssel zunächst exportieren:
    regedit /e [Dateiname] [Registry-Schlüssel]
    
In der erzeugten Textdatei kann man die Textsuche nach den gewünschten Informationen ansetzen.
Hier ein Beispiel, um die Werte eines Schlüssels anzuzeigen:

@echo off
    set REGFILE=%TEMP%\~regpart.reg
    set REGFOLDER=HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run
     
    regedit /e %REGFILE% %REGFOLDER% >nul
     
    echo [%REGFOLDER%]:
    type %REGFILE% | find "="
    del %REGFILE%
    
Bat-Beispiel

Anmerkungen:
Es werden mit regedit /e automatisch immer alle Unterschlüssel exportiert. Das obige Beispiel funktioniert nur deshalb (zufällig) korrekt, weil der gewählte Schlüssel keine Unterschlüssel besitzt.

Unter Windows XP gibt es das Kommandozeilen-Tool REG, mit dem sich Zugriffe auf die Registry einfacher gestalten.
    reg /?
    

Befehle: delechofindregregeditsettype

Seitenanfang


in die Registry schreiben

Mit Hilfe von regedit kann man via Batchfile auch die Registry verändern. Möglich sind:
  • Anlegen von Schlüsseln und Werten
  • Ändern von Werten
  • Löschen von Schlüsseln und Werten
Voraussetzung zur Manipulation der Registry ist eine ASCII-Datei, die die "Anweisungen" zum Ändern/ Löschen enthält: eben eine REG-Datei. Deren Syntax mit Angabe von Schlüsseln und Werten können Sie sich ansehen, indem Sie einen Export der Registry ausführen.
s.a. aus der Registry lesen

Um eine REG-Datei zu importieren, ist regedit mit deren Dateinamen aufzurufen. Der Import der Registry-Datei erfolgt ohne eine Rückfrage, indem man zusätzlich den Parameter /s (für silent) verwendet:
    regedit /s [REG-Datei]
    

Befehle: regregedit

Seitenanfang


Debuggen von BAT-Dateien

Einen "echten Debugger" gibt es nicht. Mit folgenden Praktiken kann man sich aber etwas behelfen:
  • Zeilenweises Ausführen von BAT-Dateien
    Das kann man lediglich mit kleinen Skripten machen.
        COMMAND /Y /C [Befehl]
                
    bzw. unter NT4, Win2000/ ME:
        CMD /Y /C [Befehl]
                

  • gezieltes Setzen von @echo on und echo off.
    Mit @echo on werden die auszuführenden Kommandos in die Standardausgabe gescrieben. Es entspricht in etwa den Optionen set -vx und set +vx in der UNIX-Shell.
        echo on
        echo Ab hier werden die ausgefuehrten Kommandos wiederholt
        echo %temp%
        (...)
    
        @echo off
        echo Ab hier wird nur die Ausgabe der Kommandos angezeigt.
        echo %temp%
                

  • Einbau von Variablenausgaben und Pausen
    Stoppen Sie die Abarbeitung des Skriptes durch den Einbau des Kommando "pause" - lassen Sie zuvor die gewünschten Variablen ausgeben.
        echo wert1=%wert1%
        echo wert2=%wert2%
        echo wert3=%wert3%
        pause
                
    Sofern die Variablen eine bestimmte Syntax haben, z.B. das Prefix "MY_", kann man mit einem find die Ausgabe der Umgebungsvariablen filtern:
        set | find /i "MY_"
        pause
                

  • Man kann sich zu Beginn des Skripts eine Variable (hier debug) setzen. Nur wenn diese auf 1 gesetzt ist, wird eine Zusatzinfo ausgegeben.
        if "%debug%"=="1" echo wert1=%wert1%

Befehle: cmdfindifset

Seitenanfang


Laufwerke verbinden/ trennen

Wenn in einem Firmennetzwerk alle User dieselben Shares mit bestimmten LW-Buchstaben verbunden haben sollen, sollte man diese am besten im Logon-Skript verarbeiten. Falls bereits ein Laufwerk verbunden sein sollte, trennt man zunächst die bestehenden Mappings.

@echo off
    echo Trenne Laufwerke...
    for %%a in (h i j k) do echo N | net use %%a: /del
    echo.
    echo Verbinde Laufwerke...
    net use H: \\SERVER_1\SHARE_1 >nul
    net use I: \\SERVER_1\SHARE_2 >nul
    net use J: \\SERVER_2\SHARE_1 >nul
    net use K: \\SERVER_3\SHARE_1 >nul
    
Bat-Beispiel


Befehle: echofornet use

Seitenanfang


Ausführung nur einmal am Tag gestatten

Um ein zweites Ausführen des Skriptes zu testen, muss man auf das letzte Ausführungsdatum zurückgreifen können. Das geht z.B., indem man sich das Ausführungsdatum bei Erfolg in einer Textdatei sichert.

Nachfolgendes Beispiel funktioniert mit der deutschen Version von Window98 (für andere Sprachen müssen die fett hervorgehobenen Texte angepasst werden):

@echo off
     
    :: -- Variablen
    set datefile=letzte_ausführung.txt
    set tmpfile=aktueller_zeitstempel.tmp
     
    :: -- aktuelles Datum in eine Datei schreiben
    echo. | date | find /i "aktuelles" > %tmpfile%
     
    :: ... und mit letztem Zeitstempel vergleichen
    fc %tmpfile% %datefile% | find "FC: Keine Unterschiede festgestellt" >nul
    if errorlevel 1 goto machwas
    echo INFO: Skript wurde heute schon einmal ausgefuehrt.
    goto ende
     
    :machwas
    echo.
    echo INFO: Hier kommen die eigentlichen Aktionen des Skripts hin
     
    :: -- aktuelles Datum als letzte Ausfuehrung vermerken.
    move %tmpfile% %datefile%
    goto ende
     
    :ende
    
Bat-Beispiel

Anmerkung zu anderen Windows-Versionen:

  • Zum Ermitteln des aktuellen Datums wird hier für Win95/ 98
    echo. | date | find /i "aktuelles" > %tmpfile%
    verwendet. Unter Win NT/2K kann einfacher
    date /t > %tmpfile%
    geschrieben werden.

  • Das Errorlevel
                    fc %tmpfile% %datefile% | find "FC: Keine Unterschiede festgestellt" >nul
                    if errorlevel 1 goto machwas
                

    ist ebenfalls typisch Windows 95/98; unter NT und neuer (Win 2000, XP, Vista, 7) kann man es wiederum sprachenunabhängig schreiben:
                    fc %tmpfile% %datefile% >nul
                    if %ERRORLEVEL%==1 goto machwas
                

Hinweis
Um die Ausführung alle n Tage zu gestatten, habe ich ein fertiges Skript:
Run_if_older

Befehle: datefcfindifset

Seitenanfang


Austauschen von Textinhalten

Die schlechte Nachricht vorweg: Man kann mit Bordmitteln und Beachtung der Abwärtskompatibilität nur ganze Zeilen austauschen. Falls wer Unix-Shellskript kennt, dem empfehle ich die Installation von CYGWIN - dann lässt sich z.B. die Bash nutzen und auch weitere Tools wie der Streameditor, awk oder tr (was man in den meisten Fällen besser gebrauchen könnte).
Mit Windows XP gibt es ebenfalls noch ein paar weitergehende Möglichkeiten.

was immer geht:

Das nachfolgende Beispiel wäre eine Anwendung für ganzzeiliges Ersetzen in Dateien: in der hosts-Datei wird der Eintrag für den (fiktiven) Rechner "testserver.example.com" ausgetauscht. Nachteile hierbei sind:
  • es werden keine Passagen, sondern eine komplette Zeile ersetzt
  • der neue Eintrag wird zuunterst in der Datei eingefügt und nicht bei der aktuellen Stelle

set hostsfile=%windir%\system32\drivers\etc\hosts
    set tmpfile=%temp%\hosts.tmp
     
    rem -- vorhandenen Eintrag entfernen und in Temp-Datei schreiben
    type %hostsfile% | find /v "testserver.example.com" >%tmpfile%
     
    rem -- neuen Eintrag der Temp-Datei hinzufügen
    echo "123.123.456.456	testserver.example.com">>%tmpfile%
     
    rem -- Temp-Datei in Hostfile umbenennen
    move %tmpfile% %hostsfile%
    
Bat-Beispiel

ab Windows XP

Man kann
  • Im set-Befehl kann man Zeichenketten ersetzen (dazu folgt gleich ein Beispiel)
    set A=%PATH:str1=str2%

    ... und Zeichen im String abschneiden, z.B. ab dem 11. Zeichen 5 Zeichen ausgeben:
    %PATH:~10,5%

    ... oder einfach den Platzhalter % für Variablen verwenden

  • In der Hilfe von For sind diverse Ersetzungen zur Zerlegung von Pfad, Dateinamen, Extension, Zeitstempel und Grösse genannt

  • auch hilfreich: das Entfernen des doppelten Hochkommas. So brauche ich oftmals das Verzeichnis des aktuellen Skripts, wenn ich im selben Verzeichnis eine Konfiguration lesen oder eine weitere Datei aufrufen will.

    unschöne Variante:
    set cfgfile=0%\..\inc_config.bat
    besser:
    set scriptdir=%~dp0%
        set cfgfile=%scriptdir%\inc_config.bat
Am besten, du schaust mal in die Hilfe-Ausgabe von
set /?
    for /?

s.a. Dateinamen/ Zeichenketten zerlegen (Win XP)


Hier noch 2 Beispiele:

Im aktuellen Verzeichnis werden die Dateinamen ermittelt (dir /b *.*). Wenn ein Umlaut auftaucht (s. Zeile set chars= ...), wird der unerwünschte Buchstabe angezeigt. Dann wird das Label :replace angesprochen. Darin wird ausgegeben, wie ein Dateiname ohne Umlaut aussehen kann. Hierzu werden mehrere Ersetzungen hintereinander durchgeführt.

Und noch ein wichtiger Hinweis: Die Umlaute/ Sonderzeichen im nachfolgenden Quelltext sind im ASCII-Modus zu schreiben- die Umlaute nicht in notepad & Co. einfügen, sondern z.B. mit edit in der Eingabeaufforderung).

    @echo off
    set chars=ä ö ü è é

    echo.
    echo ===== schlechte Dateinamen ======
    echo.

    for /F %%a in ('dir /b *.*') do (
            for %%m in (%chars%) do (
                    echo %%a | find /i "%%m">nul && echo schlecht: [%%m] in %%a
            )
            call :replace "%%a"
    )
    echo.
    echo Suche beendet. Taste druecken zum Beenden.
    pause>nul
    exit

    :replace
    set newname=%1
    set newname=%newname:ä=ae%
    set newname=%newname:ö=oe%
    set newname=%newname:ü=ue%
    set newname=%newname:è=e%
    set newname=%newname:é=e%

    if NOT "%newname%"=="%1" echo ----- Vorschlag zum Umbenennen: && echo        VON : %1 && echo        NACH: %newname% && echo.
    
Dateien mit Umlauten ausfindig machen


Beispiel 2:

Nehmen wir mal folgendes Template an:
    ::
    :: Die 2 Doppelpunkte am Zeilenanfang sind Kommentarzeichen.
    :: Durch Anpassung des findstr kann man aber auch andere Zeilen ausfiltern.
    ::

       Test-Template zum Ersetzen eines Textes

       Name: %sName%
       Vorname: %sVorname%

       Betreff: %sBetreff%

    
template.txt

... darin ersetze ich die Variablen mit %-Platzhalter (wie in der Batch- Schreibweise) mit vorgegebenen Umgebungsvariablen.
Zunächst setze ich die Variablen mit einem normalen SET. Das Template wird einmal ungefiltert ausgegeben (mit TYPE).
Dann wird die Textdatei gelesen (wobei Template-Kommentare mal ausgefiltert werden) und deren Textinhalt ersetzt.
Der Trick besteht darin, die Textzeile nicht direkt bei der for-Schleife, sondern erst im Label :replace das echo auszuführen.
Die Zeile
set line=%line:Ersetzen=Manipulieren%
ersetzt wie im obigen Beispiel einen vorgegebenen statischen Text.

    @echo off

    set template=template.txt
    set sName=Mustermann
    set sVorname=Klaus
    set sBetreff=Dies ist eine vordefinierte Betreffzeile.

    echo --- das Template:
    type %template%
    echo.
    echo --- ersetzen der Platzhalter und eines einfachen Textes:
    for /F "tokens=*" %%a in ('type %template% ^| findstr /v "^::"') do call :replace "%%a"
    echo.
    echo --- fertig.
    goto end

    :replace
    set line=%~1
    set line=%line:Ersetzen=Manipulieren%
    echo %line%
    goto end2

    :end
    pause & exit

    :end2
    
Ersetzen von Zeichen und Variablen mit %

... und das ist die Ausgabe:
    --- das Template:
    ::
    :: Die 2 Doppelpunkte am Zeilenanfang sind Kommentarzeichen.
    :: Durch Anpassung des findstr kann man aber auch andere Zeilen ausfiltern.
    ::

       Test-Template zum Ersetzen eines Textes

       Name: %sName%
       Vorname: %sVorname%

       Betreff: %sBetreff%

    --- ersetzen der Platzhalter und eines einfachen Textes:
    Test-Template zum Manipulieren eines Textes
    Name: Mustermann
    Vorname: Klaus
    Betreff: Dies ist eine vordefinierte Betreffzeile.

    --- fertig.
    Drücken Sie eine beliebige Taste . . .

Befehle: callfindfindstrforfindset


Seitenanfang


net send: an mehrere Benutzer dieselbe Nachricht senden

Mit dem Kommando net send kann man an einen Benutzer (bzw. Rechnernamen) eine Nachricht senden. Auch eine bestimmte Nachricht an die ganze Domain abzsetzen, ist mit einem einzelnen Aufruf möglich. Möchte man an ausgewählte Benutzer/ Rechner eine Botschaft senden, sind mehrere Aufrufe von net send erforderlich.

@echo off
     
    :: Liste der Empfaenger:
    set userlist=jana susi mary anna
     
    :: Hier die Nachricht eintragen:
    set sMsgText=Es gibt nun Kaffee und Kuchen fuer alle ... Euer Axel
     
    echo on
    for %%a in (%userlist%) do net send %%a %sMsgText%
    @echo off
     
    echo %0 beendet.
    pause
    
Bat-Beispiel


Befehle: echofornet sendpauseset

Seitenanfang


Pause einlegen

Manchmal braucht es zwischen 2 Aktionen in einer Batchdatei eine kleine Pause. Ein Kommando wie sleep gehört nicht zum Befehlsumfang, aber man kann sich mit dem ping-Kommando behelfen:
Der Parameter /n [Anzahl] pingt einen angegebenen Rechner entspr. der mitgegebenen Anzahl an. Dabei liegt zwischen den Pings ca. 1 Sekunde. Da der erste Ping sofort ausgelöst wird, kann man, um x Sekunden zu warten, die Anzahl (x+1) angeben.
Und was pingt man nun an? Am besten das, was immer da sein sollte: localhost.
Last but not least: Damit die ganze Ausgabe des Ping-Kommandos nicht sieht, leitet man selbige in das Nul-Device um.
@echo off
    echo.
    echo Anzeige der momentanen IP-Adresse:
    echo.
    ipconfig | find /i "ip-adresse"
    echo.
    echo ich schliesse in 5 Sekunden....
    ping /n 6 localhost >nul
    
Bat-Beispiel


Befehle: echofindipconfigping

Seitenanfang


Benutzereingabe in einer Variable speichern

Benutzereingaben lassen sich in neueren Windowsversionen mit
set /p Variablenname=[angezeigter Text]
realisieren.

Folgendes Beispiel fragt nach einer Benutzereingabe, sofern dem Skript kein Parameter mitgegeben wird. Der Benutzer bekommt einen blinkenden Cursor vorgesetzt und muss seine Eingabe, die im Klartext angezeigt wird, mit [Return] abschliessen. Der Wert wird in der Variable testvar gespeichert.
@echo off

    if "%1"=="" goto eingabe
    set testvar=%1
    goto ausgabe

    :eingabe
    set /p testvar=Irgendetwas eingeben:
    goto ausgabe

    :ausgabe
    echo Ausgabe zur Kontrolle:
    echo testvar=%testvar%

    pause
    
Bat-Beispiel

Anmerkung zu anderen Windows-Versionen:
Ich glaube, der Parameter /p beim Kommando SET existiert erst ab Windows 2000 (oder auch NT4) - auf jeden Fall funktioniert dieses Beispiel nicht mit Windows 95/98 oder DOS.


Befehle: set
Diese Eingabezeile ist zudem recht "schlicht". Wer mehr Comfort bieten möchte, kann sich WBAT auf Horst Schaeffers Batch Pages ansehen - hiermit lassen sich recht einfach ganze GUIs bauen: neben Eingabezeilen sind auch Radiobuttons, Checkboxen, Listenelemente und so einiges mehr möglich. Wie das so alles funktioniert, schaut man sich aus dem mitgeliefertem Demo ab.

Befehle: echoifgotoset

Seitenanfang


Ausgabe in mehreren Sprachen (Win XP)

Ein Ansatz für eine mehrsprachige Ausgabe wäre die Verwendung einer Textsuche. Mit Labels kann man eine Art Prozedur abhandeln wie in höheren Programmiersprachen: man kann auch Parameter übergeben - der erste ist als %1 abrufbar.

Die Suche in der Sprachendatei erfolgt nach einer Zeichenkette (Keyword + Sprachkuerzel), die sich am Zeilenanfang befinden soll:
findstr "^%1_%lang%" %langfile%

Zum Abschneiden des Prefix in der Ausgabe wird alles von einer For-Schleife umgeben und mit Hilfe der Tokens entfernt:
FOR /F "delims=_ tokens=3-6 " %%a IN ('findstr "^%1_%lang%" %langfile%') do echo%%a %%b %%c %%d
Wer die For-Anweisung jetzt nicht versteht, bekommt umfangreiche Erklärungen samt Beispiel mit dieser Eingabe im Kommandozeilenfenster:
for /?

Jetzt muss ich nur noch wissen, wie ich meine Texte anzeigen lasse:
call :DisplayInfo welcome
wobei :DisplayInfo mein angesprungenes Label in derselben Bat-Datei ist, und "welcome" mein Kürzel für den anzuzeigenden Text.

Nachteile
... dir mir bekannt sind:
  • Performance ... naja, wenn es darauf ankäme, schreibt man ja auch keine Batchfiles.
  • Variablen in den Texten werden nicht expandiert
  • In den Texten darf der Trenner zw. Keyword und Textzeile nicht verwendet werden. Das Trennzeichen wird immer herausgeschnitten
Nachfolgendes Beispiel können Sie kopieren, als BAT-Datei speichern und einmal damit experimentieren.
Hier sind die Texte in der Bat-Datei selbst untergebracht - man muss dafür sorgen, dass die Sprachtexte niemals durch die Ausführung der Datei erreicht werden können - sonst hagelt es Syntax-Fehler:
    @echo off
     
    set lang=de
    :: set lang=en
     
    set langfile=%0
     
    rem ----------------------------------------------------------------------
    ::  eigentliches Skript - Aufruf der Texte "welcome" und "pause"
    rem ----------------------------------------------------------------------
    call :DisplayInfo welcome
    call :DisplayInfo pause
    pause >nul
    goto end
     
    rem ----------------------------------------------------------------------
    ::  Modul zur Ausgabe der sprachabhaengigen Texte
    rem ----------------------------------------------------------------------
    :DisplayInfo
    FOR /F "delims=_ tokens=3-6 " %%a IN ('findstr "^%1_%lang%" %langfile%') do echo%%a %%b %%c %%d
    goto end
     
    rem ----------------------------------------------------------------------
    ::  sprachabhaengige Texte
    rem ----------------------------------------------------------------------
    welcome_de_.
    welcome_de_ Informationen
    welcome_de_.
    welcome_de_ Zeile2 ... mit etwas Text ...
    welcome_de_ Zeile3
    welcome_de_ Zeile4
     
    pause_de_ Druecken Sie [Strg]+[C] zum abbrechen ... weiter mit beliebiger anderer Taste
     
    welcome_en_.
    welcome_en_ informations
    welcome_en_.
    welcome_en_ ...
     
    pause_en_ Press [Strg]+[C] to cancel ... or any key to continue
     
    rem ----------------------------------------------------------------------
    ::  ENDE
    rem ----------------------------------------------------------------------
    :end
languagetest.bat


Befehle: callechofindstrforgotopauseset

Seitenanfang


Dateinamen/ Zeichenketten zerlegen (Win XP)

Um einen kompletten Dateinamen - bestehend aus Laufwerk, Pfad und Dateinamen - in seine Bestandteile zu zerlegen, gibt es mit dem FOR einige Ersetzungsmöglichkeiten. Mit Hilfe der Ersetzungen kann man z.B. den Pfad, den Dateinamen und die Extension erhalten.


    for /? 
Hilfe für FOR aufrufen

Bei sonstigen Zeichenketten kann man mit den Optionen delims=[Trennzeichen] und tokens=[Nr.] arbeiten, um eine Zeichenkette zerlegen.

In nachfolgendem Beispiel wird der Pfad der win.com im Windows-Verzeichnis zerlegt:

    @echo off

    set sFullname=%windir%\win.com

    for %%i in ("%sFullname%") do set sPATH=%%~di%%~pi
    for %%i in ("%sFullname%") do set sFILE=%%~ni%%~xi
    for /F "delims=. tokens=1" %%i in ("%sFILE%") do set sPart1=%%i
    for /F "delims=. tokens=2" %%i in ("%sFILE%") do set sPart2=%%i


    echo sFullname=%sFullname%
    echo sPATH=%sPATH%
    echo sFILE=%sFILE%
    echo sPart1=%sPart1%
    echo sPart2=%sPart2%

    pause
Bat-Beispiel


s.a. Bei Erreichen einer Dateigrösse etwas ausführen

Befehle: echoforset

Seitenanfang


Ausgabe eines Befehls in eine Variable holen (Win2k)

Zunächst muss man wissen, in welchem Format die Ausgabe eines Kommandos daherkommt und wie man die gesamte Ausgabe nach der gewünschten Zeile filtern kann.

Oft steht die gewünschte Information dann auch nicht allein in der Zeile - dann muss man noch die anderen Informationen ausblenden. Am einfachsten ist dies mit der FOR-Schleife zu bewerkstelligen. Mit den Parametern TOKENS und DELIMS lässt sich die Ausgabe effektiv beschneiden. Das Setzen der Variable erfolgt mit dem normalen SET Befehl.

    rem -- Beispiel 1 --
    For /F "tokens=2 Delims=:" %%i in ('ipconfig /all^|Find /i "DNS"') Do @Set DNSSERVER=%%i
    echo DNSSERVER=%DNSSERVER%
     
    rem -- Beispiel 2 --
    For /F "tokens=3" %%i in ('Net Config Workstation^|Find /i "Arbeitsstationsdom„ne"') Do @Set WORKGROUP=%%i
    echo WORKGROUP=%WORKGROUP%
     
    rem -- Beispiel 3 --
    set sTMPFILE=%temp%\~test.tmp
    regedit /e %sTMPFILE% "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion"
    For /F "tokens=2 Delims==" %%a in ('type %sTMPFILE%^| find "ProductId"') do @set winSerial=%%a 2>nul
    del %sTMPFILE%
    echo Windows-Serial Number=%winSerial%
Ausgabe eines Befehls in eine Variable packen (Windows 2000)


so holt man den Wert aus der Registry in eine Variable - das funktioniert mit Hilfe der reg.exe, die XP beiliegt:
Hinweise:
  • Der erste Befehl könnte mehrere DNS-Server zurückgeben (wg. alternativen DNS-Servern als auch bei mehreren Netzwerkkarten) - beachte, dass per Default in der For-Schleife nur der letzte Wert zurückgeliefert wird. Mehr zu dieser Eigenheit erfährst du nach Eingabe "for /?" in der Kommandozeile.
  • Das Auffinden der Workgroup oder Domäne sucht nach einem deutschen String. Bei einem anderssprachigen Betriebssystem funktioniert dieser Aufruf schon nicht mehr.
  • regedit exportiert immer alle untergeordneten Schlüssel. Unter XP sollte man reg einsetzen:
    reg QUERY HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion /v ProductId
    Dies ist wesentlich schneller und einfacher zuschreiben (aber eben nicht kompatibel zu älteren Win-Versionen).
    Dieser Aufruf ermittelt den Ordner der History des IE (alles ist in eine Zeile zu schreiben):
        For /F "tokens=3* delims=[tab_druecken]" %%i in
        ('reg QUERY "HKEY_CURRENT_USER&Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v "History" ^| findstr /i "History"')
        Do set HistoryDir=%%i
        
    Ausgabe von reg in eine Variable packen (Windows XP)


Befehle: echofindfindstrforipconfignet configregregeditsettype

Seitenanfang


HTML-Ausgabe erzeugen

Die Zeichen < und > haben in einer Batchdatei Ein- und Ausgabefunktionen. Der ganze "Trick" für eine HTML-Ausgabe besteht darin, diese Zeichen zu maskieren, damit man sie in die Ausgabe schreiben kann:

    rem -- Ausgabedatei
    set htmlout=%temp%\logfile.html

    rem -- HTML generieren
    echo ^<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"^>  >%htmlout%
    echo ^<HTML^>^<HEAD^>                                            >>%htmlout%
    echo ^<TITLE^>HTML-Ausgabe-Test^</TITLE^>                        >>%htmlout%
    echo ^</HEAD^>^<BODY^>                                           >>%htmlout%
    echo ^<H1^>HTML-Test^</H1^>                                      >>%htmlout%
    date /t                                                          >>%htmlout%
    time /t                                                          >>%htmlout%
    echo ^<HR /^>                                                    >>%htmlout%
    echo Hello world.^<HR /^>                                        >>%htmlout%
    echo ^</BODY^>^</HTML^>                                          >>%htmlout%

    rem -- Browser starten
    start %htmlout%
    
HTML ausgeben

Befehle: echostartset

Seitenanfang


eine Textdatei parsen

Oft ist es gut, wenn man Informationen aus einer Textdatei liest, statt in einer Batchdatei diese als Variablen abzulegen oder zigfach dieselbe Kommandofolge zu wiederholen. Anpassungen erfolgen dann in einer Konfigurationsdatei und derjenige, der die Anpassung macht, braucht nicht im Skript herumfuhrwerken.

Um eine Textdatei zu parsen, brauchen wir eine Textdatei, aus der wir die Informationen auslesen wollen. Neben den auslesbaren Nutzdaten sollte man Kommentare verwenden können.
Zu Demo verwende ich einmal die folgenden Konventionen:
  • Kommentare sind Zeilen, die mit # beginnen
  • Trennzeichen in meiner Konfiguration ist das Pipe-Symbol: |
... und so kann es aussehen:
# ==================================================
# DEMO-Konfiguration
# Syntax:
# Kuerzel | Anzeigename | zu startendes Programm
# ==================================================

E|Explorer|explorer.exe

W|MS Write|write.exe
P|MS Paint|paint.exe

# -- ENDE
    
Konfigurationsdatei

Wenn man ein Menü darsellen möchte, braucht man jeweils das erste und zweite Feld aus fer Konfigurationsdatei. Das Parsen erfolgt mit Hilfe des findstr-Befehls. Die Kommentare kann man mit dem Parameter /v rauswerfen. Dies zeigt alle Zeilen exklusive die mit # am Zeilenanfang:
type menu.txt | findstr /v "^#"

Desweiteren müssen wir wissen, wie wir die überbleibenden Informationen anhand unseres Trenner-Symbols auseinandernehmen können. Dies geht mit Hilfe des For-Kommandos.
Mit dem Parameter /F geben wir an, dass eine Kommandoausgabe geparst werden soll. Mit der Angabe delim wird das Trennzeichen angegeben. Innerhalb der Schleife kann man mit der angegebenen Variable auf den ersten Wert zugreifen; mit dem nächstfolgenden Buchstaben auf den zweiten Wert usw.:

    echo Programmauswahl:
    for /F "tokens=1,2 delims=|" %%a in ('type menu.txt ^| findstr /v "^#"') do (
            echo Taste %%a ... %%b
    )
    
Parsen der Textdatei


Befehle: echofor

Seitenanfang


eine zufällige Datei wählen

Um eine Datei zufällig auswählen zu können, braucht man:
  • man muss die Anzahl der Dateien als Wert in eine Variable holen
  • einen Zufallswert zw. 1 und der Anzahl der Dateien ermitteln
  • aus dem Zufallswert wieder die Datei zurordnen.
Ich lasse so z.B. den Windows-Startsound zufällig bestimmen. In der Systemsteuerung ist eine fixe Datei beim Windows-Start festgelegt. Das Batchscript wählt zufällig eine Wav-Datei aus einem Verzeichnis und überschreibt die eingestellte Sound-Datei. Zuguterletzt ist das Batchfile im Autostart-Ordner.

In den nachfolgenden Codeschnipeln hole ich mir in Variablen:
anzahlWav - Anzahl der WAV-Dateien
i - Zufallswert
myfile - meine zufällige Datei, die an Stelle i steht

Anzahl Dateien holen

In eine Variable anzahlWav hole ich die Anzahl Dateien:

    :: get count of files
    set targetfile=random.wav
    set anzahlWav=0
    for /F "tokens=1 delims=:" %%b in ('dir /b %mydir%\*.wav ^| findstr /v "%targetfile%" ^| findstr /n "." ') do set anzahlWav=%%b
    
Anzahl der Dateien ermitteln

Erläuterungen:
Ich brauche zunächst eine Liste der Dateien. Dazu hilft mir das Kommando
dir /b [Filter]

In dieser Ausgabe lasse ich nach einem beliebigen Zeichen suchen und missbrauche findstr /n ".", um eine Nummerierung der Zeilen einzufügen.
> dir /b *.wav | findstr /n "."
    1:erste_datei.wav
    2:zweite_datei.wav
    3:dritte_datei.wav
    (...)
    
Mit einem findstr /v "%targetfile%" verhindert man, dass die Zieldatei nicht mitgezählt wird.

Zufallswert

In eine Variable i sole ich meinen Zufallswert:

    set /a i=%random%*%anzahlWav%/32767+1
    
Zufallswert holen

Erläuterungen:
In der Variable %random% steckt ein Zufallswert zw. 0 und 32767. Man muss erst mit der Anzahl multiplizieren und dann durch diesen Wert dividieren, da ganzzahlig gerechnet wird.

Datei Nr. i holen

In eine Variable sourcefile hole ich die Datei an der Stelle i wieder:

    set myfile=
    for /F "tokens=2 delims=:" %%b in ('dir /b *.wav ^| findstr /v "%targetfile%" ^| findstr /n "." ^| findstr "^%i%:"') do set myfile=%%b
    
Dateinamen holen

Die Vorgehensweise ist nahezu analog dem Zählen der Datei. Nun suche ich aber in der Ausgabe noch nach meiner Nummer i, die am Zeilenanfang steht und der ein ":" folgt.

Befehle: dirfindstrforset

Seitenanfang


Bei Erreichen einer Dateigrösse etwas ausführen

In der Hilfe des FOR-Kommandos sind die Zerlegungsmöglichkeiten beschrieben.
Mit der Ersetzung %~z kann man sich die Dateigrösse angeln. Hat man selbige in einer Variable, lässt sich diese in einer IF Abfrage mit einem Wert vergleichen.

Nachdem unter Dateinamen/ Zeichenketten zerlegen (Win XP) die Variante mit dem Lesen in eine Variable mit Hilfe eines Kommandos in der FOR Schleife und SET gezeigt wurde, hier eine Variante mit CALL auf ein Label.

    rem --- Hier Dateiname angeben
    set dateiname="C:/Pfad/Dateiname.LOG"

    rem --- ab welcher Groesse soll ich reagieren?
    set limit=50000

    rem --- MAIN
    call :testsize %dateiname%
    pause && exit

    rem --- die Subroutine
    :testsize
    set groesse=%~z1

    echo %groesse% Byte - %dateiname%
    if %groesse% GTR %limit% (
            echo groesser %limit% Byte.
            rem --- hier die Aktionen definieren
            rem echo del %dateiname%
            (...)
    ) else (
            echo Limit %limit% Byte noch nicht erreicht...
    )
    
Bei Erreichen einer Dateigrösse etwas ausführen


Befehle: for

Seitenanfang