Warum funktioniert das echo in meiner for-Schleife auch mit Sonderzeichen?
Hallo,
hier geht es um eine Verständnisfrage.
Warum funktioniert das echo in der for-Schleife auch mit Sonderzeichen?
Vorab
Soweit finde ich das nicht überraschend.
Die Überraschung (für mich) folgt in der Ausgabe der zweiten Variante meiner Batch.
Meine Batch(es)
Eine Batch die ohne Fehler läuft...
...und deren Ausgabe
Wenn ich jetzt das REM von Zeile 3 zur Zeile 4 verlagere, muss ich zur Fehlervermeidung die Zeilen 9 und 23 mit einem REM versehen.
Eine Batch, die zwei weitere REM benötigt (aber nicht drei)...
...und deren Ausgabe
Meine Frage
Wieso brauche ich in der zweiten Batch kein REM für Zeile 14 und erhalte in der Ausgabe
und nicht den Fehler, den ich durch Zeile 9 und 23 (ohne REM) erhalten würde?
Gruß Frank
hier geht es um eine Verständnisfrage.
Warum funktioniert das echo in der for-Schleife auch mit Sonderzeichen?
Vorab
echo "<|&>"=>"<|&>"echo <|&>=>"|" kann syntaktisch an dieser Stelle nicht verarbeitet werden.
Soweit finde ich das nicht überraschend.
Die Überraschung (für mich) folgt in der Ausgabe der zweiten Variante meiner Batch.
Meine Batch(es)
Eine Batch die ohne Fehler läuft...
@echo off
REM set z="<|&>"
set z="abc"
echo %z%>temp.txt
echo 1. Ausgabe direkt
echo %z% mit Anfuehrungszeichen
echo %z:~1,-1% ohne Anfuehrungszeichen
for /f %%a in ('type temp.txt') do (
echo 2. Ausgabe in for
echo %%a mit Anfuehrungszeichen
echo %%~a ohne Anfuehrungszeichen
call :ausgabe %%a
)
del temp.txt
goto :eof
:ausgabe
echo 3. Ausgabe per call
echo %1 mit Anfuehrungszeichen
echo %~1 ohne Anfuehrungszeichen
goto :eof
...und deren Ausgabe
1. Ausgabe direkt
"abc" mit Anfuehrungszeichen
abc ohne Anfuehrungszeichen
2. Ausgabe in for
"abc" mit Anfuehrungszeichen
abc ohne Anfuehrungszeichen
3. Ausgabe per call
"abc" mit Anfuehrungszeichen
abc ohne Anfuehrungszeichen
Wenn ich jetzt das REM von Zeile 3 zur Zeile 4 verlagere, muss ich zur Fehlervermeidung die Zeilen 9 und 23 mit einem REM versehen.
Eine Batch, die zwei weitere REM benötigt (aber nicht drei)...
@echo off
set z="<|&>"
REM set z="abc"
echo %z%>temp.txt
echo 1. Ausgabe direkt
echo %z% mit Anfuehrungszeichen
REM echo %z:~1,-1% ohne Anfuehrungszeichen
for /f %%a in ('type temp.txt') do (
echo 2. Ausgabe in for
echo %%a mit Anfuehrungszeichen
echo %%~a ohne Anfuehrungszeichen
call :ausgabe %%a
)
del temp.txt
goto :eof
:ausgabe
echo 3. Ausgabe per call
echo %1 mit Anfuehrungszeichen
REM echo %~1 ohne Anfuehrungszeichen
goto :eof
...und deren Ausgabe
1. Ausgabe direkt
"<|&>" mit Anfuehrungszeichen
2. Ausgabe in for
"<|&>" mit Anfuehrungszeichen
<|&> ohne Anfuehrungszeichen
3. Ausgabe per call
"<|&>" mit Anfuehrungszeichen
Meine Frage
Wieso brauche ich in der zweiten Batch kein REM für Zeile 14 und erhalte in der Ausgabe
<|&> ohne Anfuehrungszeichen
und nicht den Fehler, den ich durch Zeile 9 und 23 (ohne REM) erhalten würde?
Gruß Frank
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 337648
Url: https://administrator.de/contentid/337648
Ausgedruckt am: 21.11.2024 um 22:11 Uhr
9 Kommentare
Neuester Kommentar
Hallo Frank.
Lang: Das hat etwas damit zu tun wann und wie Variablen zu ihrem Wert erweitert werden.
The Secrets Behind Batch File Interpretation
Am vollständigsten ist die Erklärung im Link von Edit2. Wenn du die Zeit hast, lies dir das mal durch...
Kurz: Normale Umgebungsvariablen werden zum Wert expandiert, bevor die Zeile ausgeführt wird. Somit werden die Sonderzeichen für den Code wirksam. FOR Variablen und Variablen die in Ausrufezeichen gefasst sind (bei eingeschalteter verzögerter Variablenerweiterung) können und werden nicht im Vorfeld expandiert. Somit werden die Sonderzeichen als normale literale Zeichen behandelt.
Grüße
rubberman
Lang: Das hat etwas damit zu tun wann und wie Variablen zu ihrem Wert erweitert werden.
The Secrets Behind Batch File Interpretation
Am vollständigsten ist die Erklärung im Link von Edit2. Wenn du die Zeit hast, lies dir das mal durch...
Kurz: Normale Umgebungsvariablen werden zum Wert expandiert, bevor die Zeile ausgeführt wird. Somit werden die Sonderzeichen für den Code wirksam. FOR Variablen und Variablen die in Ausrufezeichen gefasst sind (bei eingeschalteter verzögerter Variablenerweiterung) können und werden nicht im Vorfeld expandiert. Somit werden die Sonderzeichen als normale literale Zeichen behandelt.
Grüße
rubberman
Hehe. Es ist ratsam ein paar Regeln aufzustellen, wenn man einigermaßen sicher arbeiten will.
Eine meiner eigenen Regeln ist beispielsweise, dass ich immer versuche, den Variablenwert ohne umschließende Anführungszeichen zu speichern. Der Grund dafür ist, dass insbesondere bei der Übergabe von Argumenten an ein Script (oder eine Subroutine) Argumente mal mit und mal ohne Anführungszeichen ankommen. Beispielsweise wenn Dateien per Drag&Drop auf ein Batchscript gezogen werden. Alle Pfade die Leerzeichen enthalten, kommen automatisch mit umschließenden Anführungszeichen, alle anderen nicht. Es ist aber sehr einfach mit Hilfe der Tilde (z.B %~1) den Wert im Parameter %1 immer ohne Anführungszeichen zu bekommen (egal ob der Parameterwert mit oder ohne eingegangen ist). Ebenso einfach ist es, Anführungszeichen im Nachgang wieder um eine Variable zu setzen, wenn man sie benötigen sollte. Somit braucht man später im Script nicht mehr viel nachdenken, welcher Wert nun mit oder ohne Anführungszeichen ist. Bei der Arbeit mit Pfaden setze ich dann bspw. grundsätzlich wieder welche, weil Pfade in Anführungszeichen immer funktionieren, auch wenn sie keine Leerzeichen enthalten
Mit solchen einfachen Regeln machst du es dir wesentlich einfacher. Mal ein einfaches Beispiel:
Ziehe im Explorer einfach eine Datei auf die Batchdatei. Egal ob der Pfad Leerzeichen enthält oder nicht, der Wert von %file% ist immer ohne, die Ausgabe immer mit Anführungszeichen.
In der dritten Zeile siehst du bereits die nächste Regel. Wenn ein Wert zugewiesen wird, der ohne Anführungszeichen ist, dann kommt es an dieser Stelle zu Problemen mit Sonderzeichen. Setzt man das Variable=Wert Paar bei der SET Anweisung in Anführungszeichen, gibt es keine Probleme mehr (und man vermeidet, dass sich versehentlich mal ein Leerzeichen hinter dem Wert einmogelt, wenn man beim Schreiben des Codes nicht aufgepasst hat.)
Noch ein Schritt weiter ...
Es gibt eine Daumenregel, die besagt, dass die Zuweisung einer Variable bei ausgeschalteter, das Arbeiten mit dem Wert dann aber bei eingeschalteter verzögerter Variablenerweiterung einigermaßen sicher ist.
Machen wir ein paar Tests
1)
Klar, bereits beim SET geht's in die Hose. Also Variable=Wert in Anführungszeichen setzen:
2)
Der gleiche Fehler, jetzt aber beim ECHO. Also verzögerte Variablenerweiterung:
3)
Nanu, was ist passiert? Die Zeichenfolge ! Seid leise & hoert mir zu! wird bereits beim SET wie eine Variable behandelt. Da sie undefiniert ist, wird sie durch einen leeren String ersetzt. Also, für die Zuweisung die verzögerte Variablenerweiterung ausschalten, für die ECHO Ausgabe einschalten:
4)
Na also
Grüße
rubberman
Eine meiner eigenen Regeln ist beispielsweise, dass ich immer versuche, den Variablenwert ohne umschließende Anführungszeichen zu speichern. Der Grund dafür ist, dass insbesondere bei der Übergabe von Argumenten an ein Script (oder eine Subroutine) Argumente mal mit und mal ohne Anführungszeichen ankommen. Beispielsweise wenn Dateien per Drag&Drop auf ein Batchscript gezogen werden. Alle Pfade die Leerzeichen enthalten, kommen automatisch mit umschließenden Anführungszeichen, alle anderen nicht. Es ist aber sehr einfach mit Hilfe der Tilde (z.B %~1) den Wert im Parameter %1 immer ohne Anführungszeichen zu bekommen (egal ob der Parameterwert mit oder ohne eingegangen ist). Ebenso einfach ist es, Anführungszeichen im Nachgang wieder um eine Variable zu setzen, wenn man sie benötigen sollte. Somit braucht man später im Script nicht mehr viel nachdenken, welcher Wert nun mit oder ohne Anführungszeichen ist. Bei der Arbeit mit Pfaden setze ich dann bspw. grundsätzlich wieder welche, weil Pfade in Anführungszeichen immer funktionieren, auch wenn sie keine Leerzeichen enthalten
Mit solchen einfachen Regeln machst du es dir wesentlich einfacher. Mal ein einfaches Beispiel:
@echo off
setlocal DisableDelayedExpansion
set "file=%~1"
echo "%file%"
pause
In der dritten Zeile siehst du bereits die nächste Regel. Wenn ein Wert zugewiesen wird, der ohne Anführungszeichen ist, dann kommt es an dieser Stelle zu Problemen mit Sonderzeichen. Setzt man das Variable=Wert Paar bei der SET Anweisung in Anführungszeichen, gibt es keine Probleme mehr (und man vermeidet, dass sich versehentlich mal ein Leerzeichen hinter dem Wert einmogelt, wenn man beim Schreiben des Codes nicht aufgepasst hat.)
Noch ein Schritt weiter ...
Es gibt eine Daumenregel, die besagt, dass die Zuweisung einer Variable bei ausgeschalteter, das Arbeiten mit dem Wert dann aber bei eingeschalteter verzögerter Variablenerweiterung einigermaßen sicher ist.
Machen wir ein paar Tests
1)
@echo off
setlocal DisableDelayedExpansion
set line=Der Lehrer veraergert: Ruhe! Seid leise & hoert mir zu!
echo %line%
pause>nul
Der Befehl "hoert" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
Der Lehrer veraergert: Ruhe! Seid leise
2)
@echo off
setlocal DisableDelayedExpansion
set "line=Der Lehrer veraergert: Ruhe! Seid leise & hoert mir zu!"
echo %line%
pause>nul
Der Lehrer veraergert: Ruhe! Seid leise
Der Befehl "hoert" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
3)
@echo off
setlocal EnableDelayedExpansion
set "line=Der Lehrer veraergert: Ruhe! Seid leise & hoert mir zu!"
echo !line!
pause>nul
Der Lehrer veraergert: Ruhe
4)
@echo off
setlocal DisableDelayedExpansion
set "line=Der Lehrer veraergert: Ruhe! Seid leise & hoert mir zu!"
setlocal EnableDelayedExpansion
echo !line!
pause>nul
Der Lehrer veraergert: Ruhe! Seid leise & hoert mir zu!
Grüße
rubberman
Für Escapesequencen bei Literalen vielleicht noch dieser Link
http://www.robvanderwoude.com/escapechars.php
Aufpassen, was bei den Bemerkungen steht ...
Ich gebe also jedem uneingeschränkt Recht, der sagt dass Batch nicht mehr zeitgemäß ist und für die PowerShell plädiert.
Für mich persönlich macht das leider keinen Sinn. Ich schreibe Scripts für Automationen, die mir meinen Job erleichtern. Solange PowerShell auf unseren Firmenrechnern per GPO ausgehebelt ist, ist sie für mich nutzlos. Natürlich habe ich auch an PowerShell Kritiken. Wenn ich mir die Scripts hier im Forum ansehe, dann scheint es ein Volkssport zu sein möglichst alles in eine Zeile zu packen. Die Möglichkeit de facto alles per Pipe weiterzureichen, verleitet auch dazu. Lesbar ist das dann allerdings nicht mehr...
Grüße
rubberman
http://www.robvanderwoude.com/escapechars.php
Aufpassen, was bei den Bemerkungen steht ...
So jetzt höre ich aber auf. Das Fass hat einfach keinen Boden.
So ist es. Batch ist eine der schwersten Sprachen überhaupt. Nicht weil die Syntax so kompliziert ist und auch nicht weil der Sprachumfang so groß ist (im Gegenteil). Aber- Es ist fast unmöglich Code zu schreiben, der idiotensicher und ohne Bugs ist.
- Batch lässt unterschiedliche Datentypen vermissen. Bspw. gibt es als Typ grundsätzlich nur den String. Bestimmte Kommandos konvertieren numerische Strings on the fly zu ganzzahligen Werten, die aber auch immer einen 32 Bit breiten Signed Integer repräsentieren. Fließkommazahlen, Datums-/Zeittypen, Arraytypen, ... alles Fehlanzeige.
- Wichtige sprachliche Mittel fehlen, bspw. WHILE Schleifen. Dafür gibt's GOTO, das dazu verleitet unlesbaren und unwartbaren Spaghetticode zu schreiben.
- Batch lebt nur von den Kommandozeilentools. Die Hälfte der sogenannten Befehle sind eigentlich externe Programme (find.exe, fc.exe, more.com, wmic.exe, xcopy.exe, ...). Gibt es für ein bestimmtes Problem kein vorgefertigtes Tool, ist Ebbe. Du stößt also bei jeder Gelegenheit an die Grenzen von Batch. Das Resultat ist, das versucht wird jeden Bug, jedes undefinierte Verhalten und Sideeffects der cmd.exe und der anderen Tools zu missbrauchen und zu nutzen. In einem Code bei dem es auf Zuverlässigkeit ankommt, möchte ich so etwas nicht stehen haben ... Und - das ständige wiederholte Aufrufen von externen Programmen macht Batch sooo laaangsaaam ...
Ich gebe also jedem uneingeschränkt Recht, der sagt dass Batch nicht mehr zeitgemäß ist und für die PowerShell plädiert.
Für mich persönlich macht das leider keinen Sinn. Ich schreibe Scripts für Automationen, die mir meinen Job erleichtern. Solange PowerShell auf unseren Firmenrechnern per GPO ausgehebelt ist, ist sie für mich nutzlos. Natürlich habe ich auch an PowerShell Kritiken. Wenn ich mir die Scripts hier im Forum ansehe, dann scheint es ein Volkssport zu sein möglichst alles in eine Zeile zu packen. Die Möglichkeit de facto alles per Pipe weiterzureichen, verleitet auch dazu. Lesbar ist das dann allerdings nicht mehr...
Grüße
rubberman