Rufen Sie die Subroutine auf, deren Parameter ein Et-Zeichen in der Batchdatei enthält

Rufen Sie die Subroutine auf, deren Parameter ein Et-Zeichen in der Batchdatei enthält

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^&ampersand
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 /fSchleife 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%%&ampersand"
call :Output !val!

rem Calling with a string literal
call :Output with%%ESC%%^&ampersand

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&ampersand"
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^^&ampersand"
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 EnableDelayedExpansionerfordert 2 Escape-Zeichen:

ECHO 123 ^^& 456^^! wird ausgegeben 123 & 456!.

Außerdem solltest Du es SETimmer 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 setBefehl (Variablendefinition), geht weiter mit dem Parameter to call(Variablenverwendung) und geht weiter (aber endet bei weitem nicht) mit dem echoBefehl (Variablenverwendung).

@echo off
setlocal 
set "val=with&ampersand"
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&ampersand
problem without quotes: with
Der Befehl "ampersand" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
ok with quotes: "with&ampersand"
ok with escaping: with&ampersand
ok with for: with&ampersand

verwandte Informationen