Axels Webseite

zum Seitenanfang springen

BATch-Dateien - kleine Tipps

Codeschnipsel für BAT-Dateien.

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: copy echo

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

echo pause

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

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


Befehle: echo if goto type

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



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: dir echo if goto

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



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
(...)



Befehle: echo goto if ping rem set

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%


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: del echo find reg regedit set type

in die Registry schreiben

Mit Hilfe von regeditkann 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.o. "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: regedit

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: cmd find if set

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 



Befehle: echo for net use

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_ausfuehrung.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


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:


Befehle: date fc find if set

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%

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.



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%

    


... 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


... 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: call find findstr for set

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



Befehle: echo for net send pause set

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 



Befehle: echo find ipconfig ping

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


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: echo if goto set

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


Befehle: call echo findstr for goto pause set

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

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

Befehle: echo for set

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.

so holt man den Wert aus der Registry in eine Variable - das funktioniert mit Hilfe der reg.exe, die XP beiliegt:

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%

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


Befehle: echo find findstr for ipconfig net config reg regedit set type

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%


Befehle: echo start set

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
)


Befehle: echo for

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

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 

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

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: dir findstr for set

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.

Bei Erreichen einer Dateigrösse etwas ausführen
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...
)


Befehle: for