Wie rufe ich eine Subroutine auf, deren Parameter eine Variable ist, die ein Et-Zeichen (&) enthält?
Es liegt kein Fehler vor, aber der Aufruf scheint nie ausgeführt zu werden.
beispiel.bat
@echo off
setlocal enableDelayedExpansion
rem Doesn't work
set val=with^&ersand
call :Output !val!
rem Works fine
set val=without_ampersand
call :Output !val!
goto End
:Output
set "line=%1"
echo Called: !line!
goto :eof
End:
Ausgabe:
Genannt: without_ampersand
Bearbeiten:
Die Verwendung vonverzögerteErweiterungist nicht erforderlich. Es wurde nur in diesem Beispiel verwendet. Eine Möglichkeit, dies ohne die Verwendung von delayExpansion zu tun, ist vorzuziehen.
Die Frage konzentriert sich eher auf „Wie rufe ich auf?“ als auf „Wie lege ich die Variable anfänglich fest?“. Die Variable kann aus einer Benutzereingabe oder einer for /f
Schleife stammen (wie in meinem Fall).
Antwort1
Die Batch-Escape-Regeln sind ziemlich fies, aber das Verhalten ist völlig vorhersehbar, wenn Sie die Regeln kennen.
Die Informationen, die Sie zum Verständnis des Problems benötigen, finden Sie unterWie analysiert der Windows-Befehlsinterpreter (CMD.EXE) Skripts?in den Phasen 1, 2, 5 und 6 der akzeptierten Antwort. Aber viel Glück beim Aufnehmen dieser Informationen in naher Zukunft :-)
Es gibt zwei grundlegende Designprobleme, die zu Ihrem Problem führen: - Phase 6 verdoppelt alle Zirkumflexe, wodurch Phase 2 (tatsächlich die Phasen 1, 1,5 und 2) neu gestartet wird. - Aber Phase 2 muss &
als maskiert werden ^&
. Beachten Sie, dass es ein einzelnes sein muss ^
, kein doppeltes!
Die einzige Möglichkeit, Ihren Ansatz zum Funktionieren zu bringen, besteht darin, ihn einzuführen, ^
nachdem die Caret-Verdoppelung in Phase 6 stattgefunden hat.
@echo off
setlocal enableDelayedExpansion
set "ESC=^"
rem Calling with delayed expansion value
set "val=with%%ESC%%&ersand"
call :Output !val!
rem Calling with a string literal
call :Output with%%ESC%%^&ersand
exit /b
:Output
set "line=%1"
echo Called: !line!
goto :eof
ESC ist definiert als ^
.
Die erste Runde der Phase 1 erweitert sich %%ESC%%
zur %ESC%
zweiten Runde der Phase 1 (eingeleitet durch Phase 6) erweitert sich %ESC%
zu^
Dies ist alles völlig unpraktisch, insbesondere wenn Sie den Inhalt nicht kennen.
Die einzige sinnvolle Strategie, um zuverlässig Werte an eine aufgerufene Routine zu übergeben, ist die Übergabe per Referenz. Übergeben Sie den Namen einer Variablen, die den Zeichenfolgenwert enthält, und erweitern Sie diesen Wert innerhalb Ihrer Subroutine mithilfe der verzögerten Erweiterung.
@echo off
setlocal enableDelayedExpansion
set "val=with&ersand"
call :Output val
exit /b
:Output
set "line=!%~1!"
echo Called: !line!
exit /b
Antwort2
Wenn Sie zusätzlich ein „+“ ^
als Anführungszeichen hinzufügen, funktioniert es:
@echo off
setlocal enableDelayedExpansion
rem Doesn't work
set "val=with^^&ersand"
call :Output !val!
rem Works fine
set "val=without_ampersand"
call :Output !val!
goto End
:Output
set "line=%1"
echo Called: !line!
goto :eof
SET LOCAL EnableDelayedExpansion
erfordert 2 Escape-Zeichen:
ECHO 123 ^^& 456^^!
wird ausgegeben 123 & 456!
.
Außerdem solltest Du es SET
immer mit Anführungszeichen verwenden!
Antwort3
Die anderen Antworten haben bei mir nicht funktioniert, da das & immer noch als Befehlstrennzeichen gelesen wurde, aber mir ist Folgendes eingefallen (die letzte for-Schleife dient zur Demonstration und sollte nach Bedarf geändert oder entfernt werden):
@echo off
setlocal enableDelayedExpansion
set "file=pathwith&orwithoutampersandand!exclamation"
call :execute
exit /b
:execute
for %%A in ("%file:!=" "%") do (
if [!file_conc!]==[] (
set "file_conc=%%A"
) else (
set "file_conc=!file_conc!^^^!%%A"
)
)
set "file=!file_conc:"=!"
set "file_conc="
for %%A in ("!file:&=" "!") do (
if [!file_conc!]==[] (
set "file_conc=%%A"
) else (
set "file_conc=!file_conc!^^^&%%A"
)
)
set "file=!file_conc:"=!"
set "file_conc="
for /f "tokens=*" %%A in ('cmd /c ""!file!" "%error_log%" %ldt%" 1^>nul') do stuff
exit /b
Antwort4
Giftzeichen wie diese <>|&
sind innerhalb von Anführungszeichen sicher. Sie müssen jedes Mal Anführungszeichen verwenden, Sie müssen sie verarbeiten (definieren oder verwenden) (oder ihnen maskieren). Das beginnt mit dem set
Befehl (Variablendefinition), geht weiter mit dem Parameter to call
(Variablenverwendung) und geht weiter (aber endet bei weitem nicht) mit dem echo
Befehl (Variablenverwendung).
@echo off
setlocal
set "val=with&ersand"
call :Output "%val%"
exit /b
:Output
set "line=%~1"
set line
echo problem without quotes: %line%
echo ok with quotes: "%line%"
echo ok with escaping: %line:&=^&%
for /f "delims=" %%a in ("%line%") do echo ok with for: %%a
Ausgabe:
line=with&ersand
problem without quotes: with
Der Befehl "ampersand" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
ok with quotes: "with&ersand"
ok with escaping: with&ersand
ok with for: with&ersand