Erzeugung von ESC,CR,LF und DEL mit reinem Batch
Hallo an alle Batch Interessierten.
Zu erst, wozu das Ganze?
Weil ich Spaß daran habe mit Batch Sachen hinzubekommen die in jeder Programmiersprache vollkommen simpel sind,
und ich viel Zeit gebraucht habe all diese Sachen zu entwicklen (OK, der LF-Trick ist nicht von mir).
Wozu braucht man denn [DEL] oder ein [LF] Zeichen in einem Batchfile?
Um z.B. mit einem einzelnen echo über mehrere Zeilen eine Ausgabe machen zu können,
oder mit [DEL] bereits geschriebene Zeichen wieder zu löschen, z.B. für eine prozentuale Fortschrittsanzeige.
Jetzt erst mal der Code
Jetzt zu dem eigentlichem Teil, wie funktioniert das alles.
Das einfachste ist hierbei das LineFeed (LF).
Es wird durch eine multiline Caret ^ erzeugt mit zwei Leerzeilen.
Warum zwei? Weil das ^ eigentlich ein Escapezeichen für das folgende Zeichen ist als z.B. ^& am Zeilenende
wird aber das erste Zeilenende ignoriert und die nächste Zeile eingelesen, wenn da auch nur ein Zeilenende
gefunden wird, wird dieses "Escaped" damit ist kein Zeilenende mehr da und es wird eine weitere Zeile eingelesen,
die sollte dann leer sein, sonst wird der Inhalt an das <LF> drangehängt.
Jetzt kann natürlich der Einwand kommen, dass am Zeilenende nicht nur ein Linefeed steht sondern in der Windowswelt
eine Zeile mit <CR><LF> endet.
Das an dieser Stelle, dass <LF> genommen wird, statt des <CR> liegt daran, dass <CR> generell in dieser Phase nicht mehr existieren,
die wurden vom Parser entfernt.
Das <CR> wird daher über einen ganz anderen Weg erzeugt.
Es wird ein String erzeugt, der genau an der maximalen Länge für Strings liegt.
Dadurch kann bei dem echo !X! Befehl statt des normalen <CR><LF> Zeilenendes nur noch das <CR> ausgegeben werden.
Um an genau dieses dann zu gelangen wird noch ein weiteres <CR><LF> ausgegeben.
Die temporäre Datei enthält somit "....(ca 8000 Punkte)....<CR><CR><LF>"
Dann wird die Datei mit einem FOR /F eingelesen, dabei landet das einzelne <CR> im zweiten Token.
Da in der %%var Phase die <CR> nicht mehr entfernt werden, kann das <CR> erfolgreich einer Variablen zugewiesen werden.
Bei der Ausgabe klappt dann nur !CR!, weil in der anderen Variante %CR% das <CR> sofort wieder vom Parser entfernt wird.
Um das ESC und DEL zu erzeugen wird ein vollkommen anderer Weg verwendet.
Dazu wird der prompt Befehl genutzt, dieser erlaubt den Standard-Prompt mit $H$E umzustellen auf <DEL> und <ESC>.
Damit man allerdings dieses nicht nur auf der Kommandozeile sieht, sondern auch diesen in einem Batch auswerten kann,
wird echo on verwendet um auch innerhalb einer Batchausführung den Prompt zu sehen.
Damit man dann auch noch die Ausgabe abfangen kann wird der Teil innerhalb einer For-Loop ausgeführt.
Der einzige Teil der mir bei dem Ganzen noch nicht so recht gefällt, ist die Methode um <CR> zu erzeugen, da es praktisch auf
einen Bufferüberlauf angewiesen ist. Es ist also anzunehmen, dass dieses Verhalten vielleicht irgendwann mal entfernt wird,
oder es fehlschlägt, wenn z.B. die maximale Zeilenlänge von Microsoft geändert wird.
Hoffe es war nicht zu langweilig und es finden sich sinnvolle Anwendungen
jeb-the-batcher
Zu erst, wozu das Ganze?
Weil ich Spaß daran habe mit Batch Sachen hinzubekommen die in jeder Programmiersprache vollkommen simpel sind,
und ich viel Zeit gebraucht habe all diese Sachen zu entwicklen (OK, der LF-Trick ist nicht von mir).
Wozu braucht man denn [DEL] oder ein [LF] Zeichen in einem Batchfile?
Um z.B. mit einem einzelnen echo über mehrere Zeilen eine Ausgabe machen zu können,
oder mit [DEL] bereits geschriebene Zeichen wieder zu löschen, z.B. für eine prozentuale Fortschrittsanzeige.
Jetzt erst mal der Code
@echo off
setlocal EnableDelayedExpansion
call :CreateLF
call :CreateDEL_ESC
call :CreateCR
echo Test1: The LineFeed!lf!This is in a new line
echo(
<nul set /p ".=Test2: The DEL removes a char, press a key #"
pause > nul
echo %DEL%X - changing of # with X
echo(
echo Test3: Print the ESC %ESC%
echo(
<nul set /p ".=Test4: ##########The CR can change a line, press a key"
pause > nul
echo !CR! It works ---
goto :eof
::: LF should be used only with DelayedExpansion
:CreateLF
set LF=^
rem ** The two empty lines are neccessary, spaces are not allowed
set ^"NLF=^^^%lf%%lf%^%lf%%lf%^"
goto :eof
::: DEL and ESC can be used with and without DelayedExpansion
:CreateDEL_ESC
setlocal
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
ENDLOCAL
set "DEL=%%a"
set "ESC=%%b"
goto :EOF
)
goto :eof
::: CR should be used only with DelayedExpansion
:CreateCR
setlocal EnableDelayedExpansion EnableExtensions
set "X=."
for /L %%c in (1,1,13) DO set X=!X:~0,4094!!X:~0,4094!
echo !X! > %temp%\cr.tmp
echo\>> %temp%\cr.tmp
for /f "tokens=2 usebackq" %%a in ("%temp%\cr.tmp") do (
endlocal
set cr=%%a
rem set x=
goto :eof
)
goto :eof
Jetzt zu dem eigentlichem Teil, wie funktioniert das alles.
Das einfachste ist hierbei das LineFeed (LF).
Es wird durch eine multiline Caret ^ erzeugt mit zwei Leerzeilen.
Warum zwei? Weil das ^ eigentlich ein Escapezeichen für das folgende Zeichen ist als z.B. ^& am Zeilenende
wird aber das erste Zeilenende ignoriert und die nächste Zeile eingelesen, wenn da auch nur ein Zeilenende
gefunden wird, wird dieses "Escaped" damit ist kein Zeilenende mehr da und es wird eine weitere Zeile eingelesen,
die sollte dann leer sein, sonst wird der Inhalt an das <LF> drangehängt.
Jetzt kann natürlich der Einwand kommen, dass am Zeilenende nicht nur ein Linefeed steht sondern in der Windowswelt
eine Zeile mit <CR><LF> endet.
Das an dieser Stelle, dass <LF> genommen wird, statt des <CR> liegt daran, dass <CR> generell in dieser Phase nicht mehr existieren,
die wurden vom Parser entfernt.
Das <CR> wird daher über einen ganz anderen Weg erzeugt.
Es wird ein String erzeugt, der genau an der maximalen Länge für Strings liegt.
Dadurch kann bei dem echo !X! Befehl statt des normalen <CR><LF> Zeilenendes nur noch das <CR> ausgegeben werden.
Um an genau dieses dann zu gelangen wird noch ein weiteres <CR><LF> ausgegeben.
Die temporäre Datei enthält somit "....(ca 8000 Punkte)....<CR><CR><LF>"
Dann wird die Datei mit einem FOR /F eingelesen, dabei landet das einzelne <CR> im zweiten Token.
Da in der %%var Phase die <CR> nicht mehr entfernt werden, kann das <CR> erfolgreich einer Variablen zugewiesen werden.
Bei der Ausgabe klappt dann nur !CR!, weil in der anderen Variante %CR% das <CR> sofort wieder vom Parser entfernt wird.
Um das ESC und DEL zu erzeugen wird ein vollkommen anderer Weg verwendet.
Dazu wird der prompt Befehl genutzt, dieser erlaubt den Standard-Prompt mit $H$E umzustellen auf <DEL> und <ESC>.
Damit man allerdings dieses nicht nur auf der Kommandozeile sieht, sondern auch diesen in einem Batch auswerten kann,
wird echo on verwendet um auch innerhalb einer Batchausführung den Prompt zu sehen.
Damit man dann auch noch die Ausgabe abfangen kann wird der Teil innerhalb einer For-Loop ausgeführt.
Der einzige Teil der mir bei dem Ganzen noch nicht so recht gefällt, ist die Methode um <CR> zu erzeugen, da es praktisch auf
einen Bufferüberlauf angewiesen ist. Es ist also anzunehmen, dass dieses Verhalten vielleicht irgendwann mal entfernt wird,
oder es fehlschlägt, wenn z.B. die maximale Zeilenlänge von Microsoft geändert wird.
Hoffe es war nicht zu langweilig und es finden sich sinnvolle Anwendungen
jeb-the-batcher
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 156449
Url: https://administrator.de/contentid/156449
Ausgedruckt am: 22.11.2024 um 00:11 Uhr
8 Kommentare
Neuester Kommentar
Hallo jeb.
Na das gefällt mir doch um Längen besser
Und dass das CR gleich das erste Token ist, ist ein Umstand der das ganze noch vereinfacht.
Wieder mal ist mir eine Nebensache nicht ganz klar (schließlich will man ja dazulernen).
Warum du usebackq nutzt, statt den 8.3-Namen der Batchdatei zu verwenden, leuchtet wegen möglicher Sonderzeichen ein. Warum allerdings "%~dpf0" statt "%~f0" ist mir suspekt. Unter welchen Umständen könnte letzteres fehlschlagen?
Grüße
rubberman
Na das gefällt mir doch um Längen besser
Und dass das CR gleich das erste Token ist, ist ein Umstand der das ganze noch vereinfacht.
Wieder mal ist mir eine Nebensache nicht ganz klar (schließlich will man ja dazulernen).
Warum du usebackq nutzt, statt den 8.3-Namen der Batchdatei zu verwenden, leuchtet wegen möglicher Sonderzeichen ein. Warum allerdings "%~dpf0" statt "%~f0" ist mir suspekt. Unter welchen Umständen könnte letzteres fehlschlagen?
Grüße
rubberman
Hallo jeb.
Oooch, knapp 1000 Hits in einem Monat ist doch mehr als nur "jemand".
Schönen Abend noch
rubberman
<EDIT>
Das usebackq leuchtet doch nicht ein, schließlich verarbeitest du das Output eines Befehls und nicht die Datei selbst.
... sollte also ebenso funktionieren.
</EDIT>
Oooch, knapp 1000 Hits in einem Monat ist doch mehr als nur "jemand".
Zitat von @jeb-the-batcher:
Es ist natürlich vollkommen sinnlos %~dpf0 zu verwenden, statt direkt %~f0.
Und ich dachte schon mir wäre da was entgangen.Es ist natürlich vollkommen sinnlos %~dpf0 zu verwenden, statt direkt %~f0.
Schönen Abend noch
rubberman
<EDIT>
Das usebackq leuchtet doch nicht ein, schließlich verarbeitest du das Output eines Befehls und nicht die Datei selbst.
for /f %%a in ('copy /z "%~f0" nul') do set "cr=%%a"
</EDIT>
moin,
Das Del aus <del><space><del> besteht ist vllt nur deswegen, weil ein Einzelnes Del im Anschluss Keinen Rückschritt macht. Wenn also hinter einem Einzelnen Del kein Zeichen ist erfolgt auch kein Rückschritt.
Das SpaceZeichen ($S) hinter dem Prompt Befehl in der For-Anweisung leuchtet ja noch ein.
Aber warum wird dort ein echo on geschalten? In der Anweisung einer Forschleife ist immer ein Echo on geschalten.
wie cmd /c im Gegensatz zu cmd /q /c.
Ich hab mir jetzt die Zähne verbissen, weil ich ein = in ein <nul set /p "==" wollte. Mal sehen das löse ich noch anders.
Gruß Phil
Das Del aus <del><space><del> besteht ist vllt nur deswegen, weil ein Einzelnes Del im Anschluss Keinen Rückschritt macht. Wenn also hinter einem Einzelnen Del kein Zeichen ist erfolgt auch kein Rückschritt.
Das SpaceZeichen ($S) hinter dem Prompt Befehl in der For-Anweisung leuchtet ja noch ein.
Aber warum wird dort ein echo on geschalten? In der Anweisung einer Forschleife ist immer ein Echo on geschalten.
wie cmd /c im Gegensatz zu cmd /q /c.
Ich hab mir jetzt die Zähne verbissen, weil ich ein = in ein <nul set /p "==" wollte. Mal sehen das löse ich noch anders.
Gruß Phil