Batch-Programmierung: Programmierungshilfen

Aus Wikibooks

Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

[Bearbeiten] Ändern des Editors zum Bearbeiten von Batchdateien

Wenn man im Windows Explorer mit der Rechten-Maus-Taste (RMT) auf eine *.bat klickt, so werden einem die Befehle Öffnen und Bearbeiten angeboten.
Öffnen: führt die Batchdatei aus. Mit dem Befehl
Bearbeiten: wird die Batchdatei in den Texteditor notepad.exe zum Bearbeiten geöffnet.
Auch wenn Notpad zum Bearbeiten von Batchdateien ausreicht, so möchte man häufig doch die Batchdateien mit einem anderen, konfortableren Editor bearbeiten, der z.B. Syntaxhervorhebung (Syntaxhighlighting) beherrscht.

Um einen anderen Editor (z.b. Syn) zu verwenden, muss man in der Registry an der Stelle:

HKEY_CLASSES_ROOT\batfile\shell\edit\command 

den Standard Wert

(Standard) = %SystemRoot%\System32\NOTEPAD.EXE %1

auf den Startbefehl des entsprechenden Editors ändern. Z.B.

HKEY_CLASSES_ROOT\batfile\shell\edit\command | (Standard) = c:\Programme\Editor\syn\syn.exe %1

[Bearbeiten] Datum und Uhrzeit anzeigen

Für Log-Dateien ist es wichtig, dass man die Logeinträge mit Datum und Uhrzeit versehen kann:

echo %date:~0% - %time:~0,8% Uhr

Ergebnis: 12.01.2007 - 15:59:53 Uhr

Hierbei steht ":~0,8" für die Angabe der Stellen. Mit "0,8" wird angegeben, dass die Ausgabe der Zeit bei Position 0 beginnen soll und insgesamt 8 Stellen beinhalten soll. Die maximale Stellenanzahl ist 11 (0,11).

Beim Datum ist diese Angabe hier nicht nötig, da dieses standardmäßig im dd.mm.yyyy-Format ausgegeben wird. Wer aber nur das Jahr haben will, kann "%date:~-4%" eingeben und erhält damit die letzten 4 Zeichen. Für ein sortiergerechtes Datum in der Umgebungsvariablen sortdate sorgt z.B.

set SORTDATE=%date:~-4%-%date:~3,2%-%date:~0,2%
echo %SORTDATE%

Wert der Umgebungsvariable: 2009-04-20

Beachte:
In einer Batchdatei kann die Verwendung von %DATE% und insbesondere von %TIME% dazuführen, das die ausgegebene Uhrzeit sich nicht aktualisiert.
Hierzu folgendes Beispiel:

@echo off
echo ## Die aktuelle Zeit ist: %TIME%
echo ## bitte ca. 5 Sec. warten ...
ping -n 5 localhost>NUL
echo ## jetzt sollten ca. 5 Sec. vergangen sein, TIME liefert %TIME%, das ist noch OK
echo ## doch in der FOR Schleife wird bereits die alte Zeit verwendet.
for /L %%N IN (0, 1, 3) DO (
	echo %time%
	pause
	)
echo ## und dies beleibt fuer jede Ausgabe innerhalb der FOR-Schleife so.
echo.
echo ## Auch in z.B. IF-Schleifen ist das so.
if TRUE==TRUE (
		echo 1. Zeit in der If Schleife: %TIME%
		echo Warte ca. 5 Sec.
		ping -n 5 localhost >NUL
		echo 2. Zeit in der If Schleife: %TIME%
		echo Warte nochmals ca. 5 Sec.
		ping -n 5 localhost >NUL
		echo 3. Zeit in der If Schleife: %TIME%
		)
echo ## Dabei ist es bereits: %TIME%
pause

Damit %DATE% und %TIME% die richtigen Werte ausgeben, muss unbedingt die verzögerte Erweiterung von Umgebungsvariablen mit dem Befehl SETLOCAL ENABLEEXTENSIONS aktiviert werden.
Hier das korrekte Beispiel:

@echo off
SetLocal EnableDelayedExpansion
echo ## Die aktuelle Zeit ist: !time:~0,8!
echo ## bitte ca. 5 Sec. warten ...
ping -n 5 localhost>NUL
echo ## jetzt sollten ca. 5 Sec. vergangen sein, TIME liefert !TIME!, das ist OK
echo ## Jetzt gibt auch die FOR Schleife die korrekte Zeit aus.
for /L %%N IN (0, 1, 3) DO (
	echo !TIME!
	pause
	)
echo.
echo ## Auch in z.B. IF-Schleifen ist es jetzt richtig.
if TRUE==TRUE (
		echo 1. Zeit in der If Schleife: !TIME!
		echo Warte ca. 5 Sec.
		ping -n 5 localhost >NUL
		echo 2. Zeit in der If Schleife: !TIME!
		echo Warte nochmals ca. 5 Sec.
		ping -n 5 localhost >NUL
		echo 3. Zeit in der If Schleife: !TIME!
		)
echo ## Es ist jetzt: !TIME!
EndLocal
pause

[Bearbeiten] Ausgaben besser anzeigen

Wenn man nicht die Ausgabe von Befehlen per @echo off "Ausblendet" kann man am besten das Prompt ändern, sodass man besser erkennen kann, was passiert:

@prompt -$G

Der Prompt ist dann ->

[Bearbeiten] Unterroutinen und Unterprogramme

Unterroutinen kann man mittels goto oder call und Unterprogramme mit Hilfe von call realisieren.

 call:unterroutine Hallo
 echo Fertig!
 goto:eof

 :unterroutine
    echo Übergebener Parameter an Unterroutine: %1
 goto:eof

Beachten Sie, dass beim Aufruf von Unterroutinen per call Sie Probleme mit Filehandles bekommen können. Dies liegt darin begründet, dass ein Aufruf per call als Aufruf eines Unterprogramms interpretiert wird, während es sich bei goto stets um Unterroutines handelt.

Anmerkung: goto:eof ist eine Spezialmarke mit der Sie stets zum Ende Ihres Skriptes (bzw. Ihrer Unterroutine) springen

[Bearbeiten] Benutzereingaben mittels "set /P"

@echo off
    set /P w= [i]nstallieren / [d]eInstallieren?
    REM die option /I beim if bewirkt, dass nicht
    REM zwischen Gross und Kleinschreibung
    REM unterschieden wird.
    if /I "%w%"=="i" goto Install
    if /I "%w%"=="d" goto Deinstall
    echo Fehler: [%w%]
goto ende

:Install
    echo "installieren" ausgewählt
goto ende

:Deinstall
    echo "deInstallieren" ausgewählt
goto ende


:ende
    echo.
    pause

[Bearbeiten] stdout in Umgebungsvariable speichern

Falls man den stdout in einer Umgebungsvariable speichern möchte, muss man das komplizierter umsetzen. Es gibt zwei verschiedene Möglichkeiten dies anzugehen. befehl | set /P variable= funktioniert nämlich nicht. Stattdessen braucht man:

BEFEHL > temp.txt
set /p BefehlOutput= < temp.txt
del temp.txt

Oder:

FOR /F %%i IN ('BEFEHL') DO set BefehlOutput=%%i

Oder mit "usebackq"-Option:

FOR /F "usebackq" %%i IN (`BEFEHL`) DO set BefehlOutput=%%i

Die Zeichenkette zwischen den einfachen Anführungszeichen wird dabei als Befehlszeile betrachtet und von einer untergeordneten CMD.EXE ausgeführt. %BefehlOutput% kann nun beliebig gebraucht werden.

[Bearbeiten] Beispiel:

Code:

@echo off
FOR /F %%i IN ('CD') DO set verzeichnis=%%i
echo %verzeichnis%

Ausgabe:

C:\Programme\Batch

Vorsicht ist geboten, bei Befehlen, welche mehrzeilige Ausgaben produzieren und bei solchen, welche in ihrer Ausgabe auch Leerzeichen enthalten können. Da das Standardtrennzeichen ein Blank ist muss man, wenn man nicht will, dass die Variable nur bis zum Blank gefüllt wird, das Standardtrennzeichen verändern. FOR /F "delims=" %%i IN ('CD') DO set verzeichnis=%%i entfernt jede Art von Trennzeichen. Bei Befehlen, welche mehrzeilige Ausgaben zur Folge haben, bleibt jeweils die letzte Zeile in der Variablen erhalten.

[Bearbeiten] Dateien und Verzeichnisse auflisten

Hier ist ein Beispiel, in dem alle Dateien, auf welche die Filterbedingung zutrifft, aufgelistet werden. Ausserdem werden die Dateianzahl und die Dateigrößen zusammenaddiert.

@echo off
set Filter=*.*
set /A DateiAnzahl=0
set bytes=0

for /R %pfad% %%f in (%Filter%) do (
    set /A DateiAnzahl += 1
    echo %%f - %%~zfBytes
    set /A bytes=bytes+%%~zf
)

echo.
echo %~dp0%Filter%
echo Es sind %DateiAnzahl% Dateien vorhanden.
echo Alle Dateien zusammen: %bytes%Bytes
set /A kbytes=bytes/1024
echo umgerechnet sind das %kbytes% KBytes
echo.
pause

[Bearbeiten] Pause

Oft ist es hilfreich, dass ein nach dem Beenden des Batch-Programms das Eingabeaufforderungsfenster offen bleibt. So kann man Ausgaben nachlesen oder evtl. aufgetretene Fehler entdecken. Nun könnte man einfach am Ende eine pause einfügen. Dabei kann der User einfach das Fenster schließen oder ENTER drücken. Man kann aber auch einfach eine zeitliche Pause mit ping realisieren:

@echo off
echo Ich schließe gleich.
@ping localhost -n 2 >NUL

Dabei kann man die Zeit mit dem Parameter -n variieren.

Bei installiertem Resourcekit steht der Befehl "sleep" zur Verfügung welcher dieselbe Funktionalität (zeitliche Pause) bietet.

[Bearbeiten] Minimiert ausführen

Hin und wieder ist es sinnvoll, dass die Batchdatei minimiert ausgeführt wird (z. B. eine Login-Batch-Datei). Es ist möglich, dass man die Batchdatei normal startet und sie sich selber minimiert ausführt. Der Nachteil ist allerdings, dass sich kurzzeitig ein Eingabeaufforderungs-Fenster öffnet.

@echo off
if not "%1"=="" goto %1

start /MIN cmd.exe /C "%~nx0 begin"
goto:eof

:begin
    echo Hallo, ich laufe minimiert!
    pause
goto:eof

Noch eine Konstruktion ganz ohne Labels, nach diesem Newsgroup-Beitrag

@set !=||(set !=1&start "%~dpnx0" /min cmd /c %0 %*&set !=&goto :eof)

[Anmerkung zum Newsgroup-Beitrag] Sollte die Command-Processor-Option "DelayedExpansion" in der Registry aktiviert sein (siehe unter Hilfe "cmd /?"), lässt sich ein "!" als Variablenname nicht verwenden. In diesem Fall -bzw. sinnvollerweise immer- den Variablennamen ändern auf x oder y oder # oder @....

Beispiel: @set #=||(set #=1&start "%~dpnx0" /min cmd /c %0 %*&set #=&goto :eof)

[Bearbeiten] Mittels start /LOW die Priorität festlegen

Manchmal ist es hilfreich, wenn die Batchdatei mit einer niedrigen Priorität läuft. Das kann man mittels start /LOW erreichen. Weitere Optionen sind NORMAL, HIGH, REALTIME, ABOVENORMAL und BELOWNORMAL. Das Beispiel zeigt, wie eine Batchdatei quasi sich selber in die niedrige Priorität versetzten kann. In dem Fall klappt es allerdings nur, wenn beim ersten Start kein Parameter übergeben wurde.

@echo off
if "%1"=="" (
    start /WAIT /LOW /B cmd.exe /V /C %~s0 weiter_machen
    goto:eof
)
echo Jetzt laufe ich mit niedriger Priorität!
echo Überprüfe es im Taskmanager!
pause

Funktionsweise: Das Prinzip ist eigentlich ganz einfach. Wenn kein Parameter übergeben wird, wird angenommen, das die Batchdatei zum ersten mal gestartet wurde. Die if "%1"=="" Bedingung ist also erfüllt. Mittels start wird dann die selbe Batchdatei mit veränderter Priorität gestartet, allerdings mit einem angehängten Parameter weiter_machen (Könnte auch irgendwas anderes sein!) Somit ist beim nächsten Aufruf die if "%1"=="" Bedingung nicht mehr erfüllt und der normale Teil der Batchdatei wird abgearbeitet.

Wenn man der Batchdatei einen Parameter übergeben möchte (z.B. ein Dateiname o.ä.) muß man alle Parameter verschieben:

@echo off
if "%2"=="" (
    start /WAIT /LOW /B cmd.exe /V /C %~s0 %1 weiter_machen
    goto:eof
)
echo Jetzt laufe ich mit niedriger Priorität!
echo Nun kann [%1] 'bearbeitet' werden...
pause

Anmerkungen: Normalerweise könnte man statt %~s0 auch "%~0" bei der cmd.exe Zeile verwenden. Allerdings klappt das nicht richtig, wenn Leerzeichen in der Batch Datei vorhanden sind. Mit %~s0 wird der komplette Pfad zur Batchdatei als "Kurznamen" angegeben. In dem Pfad kommt dann keine Leerzeichen vor.

[Bearbeiten] Probleme mit Variablen

Wenn man sich die Hilfeseiten zu set (mittels set /?) durchliest, stößt man auf das Thema verzögerte Erweiterung von Variablen. Das will ich hier mal anhand von Beispielen erklären:

[Bearbeiten] Das Problem

set test=1
if "%test%"=="1" (
    set test=2
    echo Wert von 'test' im IF-Block: %test%
)
echo Wert von 'test' nach IF-Block: %test%

Man sollte meinen, dass der Wert von %test% in beiden Ausgaben 2 ist. Doch leider ist es nicht so. Denn innerhalb des IF-Blocks wird das Neusetzen der Variable test von 1 auf 2 noch nicht aktiv und somit ist das Ergebnis Wert von 'test' im IF-Block: 1 Erst nach dem IF-Block ist der Wert aktualisiert: Wert von 'test' nach IF-Block: 2

[Bearbeiten] Lösung: cmd.exe /V

In einer Batchdatei die mit cmd /V gestartet wurde, werden Variablen innerhalb von Befehlsblöcken aktualisiert. Jedoch kann man sie nicht gewohnt mit %test% ansprechen, sondern mit !test!

@echo off
if "%1"=="" (
    start /WAIT /B cmd.exe /V /C "%~0" machen!
    goto:eof
)
set test=1
if "%test%"=="1" (
    set test=2
    echo Wert von 'test'-Prozent in dem IF-Block: %test%
    echo Wert von 'test'-Ausrufezeichen in dem IF-Block: !test!
)
echo Wert von 'test' nach dem IF-Block: %test%
pause

[Bearbeiten] Ausgaben/Fehler unterdrücken

Manchmal möchte man per Batch ein Programm starten aber es sollen dabei keine Ausgabe gemacht werden. Das ist recht einfach:

MeinProgramm.exe >NUL

Es könnte aber sein, dass evtl. Fehler dennoch ausgegeben werden. Das liegt daran, das die Programme in dem Fall auf stderr statt stdout schreiben. Um auch in dem Fall die Ausgabe zu unterdrücken, kann man mit einem zusätzlichen 2>&1 die Ausgaben von stderr auf stdout umleiten. Da stdout dann nach NUL verschoben wird, sieht man absolut nichts:

MeinProgramm.exe >NUL 2>&1

[Bearbeiten] Professionelle Message-Fenster erzeugen

Bisher konnte man in Batch keine Fenster erzeugen, bzw. nur in Windows XP mithilfe des Windows Nachrichtendienstes. Doch der ist für Anwendungen viel zu unpraktisch, da man nicht einmal den Fenstertitel bestimmen kann und außerdem ist dieser unter Vista oder Windows 2000 nicht verfügbar.

Ich habe jedoch ein kleines Schlupfloch gefunden, mit dem man dennoch Fenster erzeugen kann:

@echo off
Echo msgbox"Text",0,"Fenstername" >Test.vbs 
ping localhost -n 3 -w 1000 >NUL
start Test.vbs
pause

Erklärung: Man erzeugt hier mithilfe des Operators > einen Temporären VBScript, der in der Lage ist, ein Messagefenster zu erzeugen. Dies sorgt in Anwendungen für mehr Übersicht und Professionalität.

[Bearbeiten] Falls das nicht funktioniert

Falls statt eures Textes die Meldung :

"Der Zugriff auf den Windows Scripthost ist auf diesem Computer deaktiviert"... erscheint, dann ist das Öffnen von VBscripts und JScripts aus Sicherheitsgründen verboten.

Um das zu ändern, öffnet ihr den Windows Registrierungseditor (regedit.exe) und löscht NUR folgenden Wert :


HKey_Local_Machine\Software\Microsoft\WindowsScriptHost\Enabled


dann dürfte es funktionieren. Erstellt vor der Änderung eine Sicherheitskopie eurer Werte !!!

Persönliche Werkzeuge