Unverständlicher Tokenizer in Klammern
Bei dem Versuch den Batch-Tokenizer (der eine Zeile in einzelne Teile zerlegt), dachte ich einem guten Modell zur Erklärung schon recht nah zu sein.
Aber dann habe ich, ein mir vollkommen unerklärliches Phänomen entdeckt.
Das es Probleme mit Labeln in Klammern gibt ist ja schon länger bekannt.
Bisher war ich der Meinung, das Label nur als letztes in einem Klammerblock verboten sind
aber dann bin ich auf einen Beitrag gestoßen, bei dem auch innerhalb eines Blocks ein Problem entsteht.
Dann habe ich noch ein wenig gespielt, und bin auf ein noch ungewöhlicheres Verhalten gestoßen
Ausgabe
Ohne Klammern ist das Verhalten normal, das Caret am Ende wird als Multiline ausgewertet, die nächste Zeile wird gelesen, da die aber leer ist wird das <LF> der leeren Zeile Escaped, damit ist kein Zeilenende mehr da und die nächste Zeile wird auch noch an das Multiline dran gehängt.
Varianten davon
Ausgabe
Aber wie kann man das verschwinden eines einzelnen Token in der Klammer erklären ?
jeb
Aber dann habe ich, ein mir vollkommen unerklärliches Phänomen entdeckt.
Das es Probleme mit Labeln in Klammern gibt ist ja schon länger bekannt.
Bisher war ich der Meinung, das Label nur als letztes in einem Klammerblock verboten sind
@echo off
(
:MeinLabel
echo Klappt
)
(
echo Klappt nicht
:MeinLabel
)
aber dann bin ich auf einen Beitrag gestoßen, bei dem auch innerhalb eines Blocks ein Problem entsteht.
@echo off
(
echo start
:comment
:comment
echo KLAPPT
)
(
echo start
::comment
:comment
echo KLAPPT
)
(
echo start
:comment
::comment
echo KLAPPT nicht
)
Dann habe ich noch ein wenig gespielt, und bin auf ein noch ungewöhlicheres Verhalten gestoßen
@echo off
(
:label eins zwei drei ^
WegIsses echo two three
echo Nur das erste Token ist weg
)
echo ---
(
:label eins zwei drei^
WegIsses echo two three
echo Jetzt ist es ganz weg
)
:label eins zwei drei ^
WegIsses echo two three
echo Ohne Klammer ist es immer weg
Ausgabe
two three
Nur das erste Token ist weg
---
Jetzt ist es ganz weg
---
Ohne Klammer ist es immer weg
Nur das erste Token ist weg
---
Jetzt ist es ganz weg
---
Ohne Klammer ist es immer weg
Ohne Klammern ist das Verhalten normal, das Caret am Ende wird als Multiline ausgewertet, die nächste Zeile wird gelesen, da die aber leer ist wird das <LF> der leeren Zeile Escaped, damit ist kein Zeilenende mehr da und die nächste Zeile wird auch noch an das Multiline dran gehängt.
Varianten davon
@echo off
setlocal EnableDelayedExpansion
echo Hallo ^
Dies zeigt einen Text mit Zeilenumbruch
echo -----
set lf=^
rem Zwei Leerzeilen sind wichtig, damit wird jetzt ein einzelnes LF erzeugt
rem Allerdings kann man ein LF nur mit DelayedExpansion ausgeben
echo Erste Zeile!LF!Zweite Zeile
Ausgabe
Hallo
Dies zeigt einen Text mit Zeilenumbruch
Erste Zeile
Zweite Zeile
Dies zeigt einen Text mit Zeilenumbruch
Erste Zeile
Zweite Zeile
Aber wie kann man das verschwinden eines einzelnen Token in der Klammer erklären ?
jeb
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 151317
Url: https://administrator.de/contentid/151317
Ausgedruckt am: 08.11.2024 um 21:11 Uhr
12 Kommentare
Neuester Kommentar
Hallo jeb,
unverständlich ist und bleibt das für mich auch.
Vielleicht liegt des Rätsels Lösung in der Art und Weise wie mit Zeilenumbrüchen in Multilines umgegangen wird.
Ausgabe:
Die Frage ist, woher kommen die Leerzeichen (hinter "Test" im ersten Beispiel bzw. vor dem zweiten echo im zweiten Beispiel). Werden Zeilenumbrüche tatsächlich als Leerzeichen interpretiert bzw. wird ein zusätliches Leerzeichen angehängt? Kann eigentlich nicht sein, denn die Erzeugung des Line Feed Characters würde auch im Multiline Block funktionieren.
Ausgabe:
Andererseits deutet einiges auf die Ersetzung des Zeilenumbruches hin. Ein Caret escapet ja normalerweise nur ein Zeichen. Der "normale" Zeilenumbruch besteht aber aus CR+LF. Zwei Zeichen, hmm...
Und wenn man sich die Erzeugung des LF Characters ansieht, käme ja noch ein zusätzliches CR dazu, das es zu escapen gilt.
Noch habe ich da auch keine Idee, wie man nachvollziehbar testen kann.
Grüße
rubberman
unverständlich ist und bleibt das für mich auch.
Vielleicht liegt des Rätsels Lösung in der Art und Weise wie mit Zeilenumbrüchen in Multilines umgegangen wird.
@echo off &setlocal &prompt ¯¯¯ &echo on
(
echo Test
)
(
echo Hallo
echo Test
)
»»» (echo Test )
Test
»»» (
echo Hallo
echo Test
)
Hallo
Test
@echo off &setlocal enabledelayedexpansion &prompt ¯¯¯ &echo on
(
set LF=^
)
echo a!LF!b
»»» (set LF=
)
»»» echo a!LF!b
a
b
Und wenn man sich die Erzeugung des LF Characters ansieht, käme ja noch ein zusätzliches CR dazu, das es zu escapen gilt.
Noch habe ich da auch keine Idee, wie man nachvollziehbar testen kann.
Grüße
rubberman
Hat jetzt nicht wirklich mit diesem Thema zu tun sondern vielleicht eher ein allgemeinerer Kommentar:
Ich würde solche "fragwürdigen" Konstrukte wie Excape Zeichen am ende der Zeile und dergleichen einfach nicht benutzen. Da mach ich mit bei einer batch Datei lieber etwas ausführlicher und mehr Arbeit und dafür vermeide ich so Sachen ...
Ich würde solche "fragwürdigen" Konstrukte wie Excape Zeichen am ende der Zeile und dergleichen einfach nicht benutzen. Da mach ich mit bei einer batch Datei lieber etwas ausführlicher und mehr Arbeit und dafür vermeide ich so Sachen ...
Hallo miniversum.
Ich gebe dir ja Recht. Man muss es nicht nutzen, es gibt bessere Möglichkeiten. Aber das ist auch nicht der Sinn der Übung.
Es geht nur darum herauszufinden, wie cmd.exe solchen Code verarbeitet, um möglichst allgemeingültige Regeln davon abzuleiten. Das wiederum hilft, wenn irgendein Batchfile nicht so funktioniert, wie man es erwartet. Ggf. findet man dann den Grund und bestenfalls auch eine Lösung ...
Ich persönlich finde es sehr gut, dass sich mal jemand mit dieser "Grundlagenforschung" beschäftigt. Das Internet hat da so gut wie nichts parat.
Grüße
rubberman
Ich gebe dir ja Recht. Man muss es nicht nutzen, es gibt bessere Möglichkeiten. Aber das ist auch nicht der Sinn der Übung.
Es geht nur darum herauszufinden, wie cmd.exe solchen Code verarbeitet, um möglichst allgemeingültige Regeln davon abzuleiten. Das wiederum hilft, wenn irgendein Batchfile nicht so funktioniert, wie man es erwartet. Ggf. findet man dann den Grund und bestenfalls auch eine Lösung ...
Ich persönlich finde es sehr gut, dass sich mal jemand mit dieser "Grundlagenforschung" beschäftigt. Das Internet hat da so gut wie nichts parat.
Grüße
rubberman
Zitat von @jeb-the-batcher:
Wenn man wissen möchte wie und warum etwas funktioniert, muss man sich eben Tests ausdenken die etwas über die inneren
Strukturen verraten.
Ohne sowas würden wir noch in Höheln wohnen und die Erde für eine Scheibe halten(und den Batch Interpreter für
einen Zufallsgenerator)
1. Testest du das mit allen Windowsversionen und alles Servicepacks? Kannst du sicherstellen das sich nicht ab einem gewissen Versionsstand das Verhalten anders ist?Wenn man wissen möchte wie und warum etwas funktioniert, muss man sich eben Tests ausdenken die etwas über die inneren
Strukturen verraten.
Ohne sowas würden wir noch in Höheln wohnen und die Erde für eine Scheibe halten(und den Batch Interpreter für
einen Zufallsgenerator)
2. Würdest du nach deiner "Untersuchung" solche Konstrukte wirklich ruhigen Gewissens verwenden?
3. Was nützt dir diese "Untersuchung" undokumentierter Funktionen für die du keine Garantie hast das es nicht doch noch Ausnahmefälle geben wird die ein anderes Verhalten hervorrufen?
4. Praktischer nutzen?
Stimmt.
Was ist aber mit den (zumindest angezeigten) zusätzlichen Leerzeichen? Irgendetwas muss im Multiline Block anders laufen als sonst.
Grüße
rubberman
Was ist aber mit den (zumindest angezeigten) zusätzlichen Leerzeichen? Irgendetwas muss im Multiline Block anders laufen als sonst.
Grüße
rubberman
Nur so ein Beispiel warum ich das Problematisch sehe. Dein Code:
ergibt bei mir (Windows xp pro mit sp3 und den aktuellen Updates) :
und
ergibt:
Also hast du hier anscheinend schon Unterschiede, nur mal als ein Beispiel.
Der Vergleich mit ANSI-C ist auch interessant weil ich selbst aus Erfahrung weiß das verschiedene (mehr oder weniger gute, aber angeblich immer ANSI konforme Compiler) den identischen C Code in unterschiedlichen Maschinencode umsetzen können, wenn es z.B. um Strukturen geht.
Das Argument
Und da Fehler und unerwartetes Verhalten in Batch Skripten erwiesenermaßen abhängig von der Version und der eingestellten Sprache ist (ja das ist bei einigen Befehlen wirklich so) und ich auch schon Unterschiede in Abhängigkeit vom Speicherort der Batch Datei (Lokal oder Netzwerkpfad) erlebt habe bevorzuge ich es eben solche "grenzwertigen" Konstrukte nicht zu benutzen und im Fehlerfall lieber das echo off bzw. an der betreffenden Stelle ein echo on einzufügen um zu sehen was wirklich geschieht.
echo Zeig mir ein Prozent %%
echo Zeig mir ein Ampersand ^&
echo Zeig mir ein Ausrufezeichen ^^!
Zeig mir ein Prozent %
Zeig mir ein Ampersand &
Zeig mir ein Ausrufezeichen ^!
echo Zeig mir ein Ausrufezeichen ^!
Zeig mir ein Ausrufezeichen !
Also hast du hier anscheinend schon Unterschiede, nur mal als ein Beispiel.
Der Vergleich mit ANSI-C ist auch interessant weil ich selbst aus Erfahrung weiß das verschiedene (mehr oder weniger gute, aber angeblich immer ANSI konforme Compiler) den identischen C Code in unterschiedlichen Maschinencode umsetzen können, wenn es z.B. um Strukturen geht.
Das Argument
1. Ich teste mit den Versionen die ich habe, und ich gehe davon aus, dass auch bei Microsoft niemand etwas ohne guten Grund ändert.
schließt ja nicht aus, dass mit einem bestimmtem Update dennoch eine Änderung dazu kommt, der Programmierer auch den Grund kennt, Du aber nicht.Und da Fehler und unerwartetes Verhalten in Batch Skripten erwiesenermaßen abhängig von der Version und der eingestellten Sprache ist (ja das ist bei einigen Befehlen wirklich so) und ich auch schon Unterschiede in Abhängigkeit vom Speicherort der Batch Datei (Lokal oder Netzwerkpfad) erlebt habe bevorzuge ich es eben solche "grenzwertigen" Konstrukte nicht zu benutzen und im Fehlerfall lieber das echo off bzw. an der betreffenden Stelle ein echo on einzufügen um zu sehen was wirklich geschieht.
Erstaunlich ^^
Ähnliches hatte ich auch getestet, war aber mit dem Leerzeichen als vermeintlichen Übeltäter auf der falschen Fährte.
Der letzte Code endete bei mir erst mal in einem Fehler (Leerzeichen im Name ).
... schaffte Abhilfe.
Grüße
rubberman
Ähnliches hatte ich auch getestet, war aber mit dem Leerzeichen als vermeintlichen Übeltäter auf der falschen Fährte.
Der letzte Code endete bei mir erst mal in einem Fehler (Leerzeichen im Name ).
(
echo 1
:label der eine Sonderbehandlung der naechsten Zeile erzeugt
:\..\%~snx0&echo Und dadruch sehen wir dies
)
Grüße
rubberman