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
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
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
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%
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
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
ÂÂ
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 /?
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%
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
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
)
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.
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