如何呼叫參數為包含與號 (&) 的變數的子程式?
沒有錯誤,但呼叫似乎永遠不會執行。
範例.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:
輸出:
稱為:without_&sand
編輯:
的用法延遲擴張不需要。它只是在這個例子中使用的。首選不使用延遲擴展的方法。
問題集中在“我如何調用”而不是“我最初如何設定變數”。該變數可能來自用戶輸入或for /f
循環(就像我的情況)。
答案1
批量轉義規則非常令人討厭,但如果您了解規則,則行為是完全可以預測的。
要了解問題所需的信息,請訪問:Windows 命令解釋器 (CMD.EXE) 如何解析腳本?在已接受答案的第 1、2、5 和 6 階段。但祝你好運,盡快吸收這些資訊:-)
有兩個基本設計問題會導致您的問題: - 在第 6 階段將所有插入符號加倍,然後重新啟動第 2 階段(實際上是階段 1、1.5 和 2)。 - 但第 2 階段需要&
轉義為^&
。注意一定是單次^
,不能是雙次!
^
讓您的方法發揮作用的唯一方法是在第 6 階段插入符號加倍發生後引入。
@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 定義為保存^
.
第 1 階段的第一輪擴展%%ESC%%
到%ESC%
第 1 階段的第二輪(由第 6 階段發起)擴展%ESC%
到^
這完全不切實際,尤其是當您不知道內容是什麼時。
將任何值可靠地傳遞到 CALLed 例程中的唯一明智策略是按引用傳遞。傳遞包含字串值的變數的名稱,並使用延遲擴展在子例程中擴展該值。
@echo off
setlocal enableDelayedExpansion
set "val=with&ersand"
call :Output val
exit /b
:Output
set "line=!%~1!"
echo Called: !line!
exit /b
答案2
如果添加額外的引號^
和引號,它將起作用:
@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
需要 2 個轉義字元:
ECHO 123 ^^& 456^^!
將輸出123 & 456!
.
您還應該使用SET
帶有引號的always!
答案3
其他答案對我不起作用,因為 & 仍然被讀取為命令分隔符,但我想出了這個(最後一個 for 循環用於演示,應根據需要修改或刪除):
@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
答案4
像這樣的毒字符<>|&
在引號內是安全的。您每次都必須使用引號,必須處理(定義或使用)它們(或轉義它們)。從set
命令(變數定義)開始,以參數 to(變數用法)繼續,然後以命令(變數用法)call
繼續(但到目前為止還沒有結束) 。echo
@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
輸出:
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