呼叫批次檔中參數包含&符號的子例程

呼叫批次檔中參數包含&符號的子例程

如何呼叫參數為包含與號 (&) 的變數的子程式?

沒有錯誤,但呼叫似乎永遠不會執行。

範例.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:

輸出:

稱為: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%%&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 定義為保存^.
第 1 階段的第一輪擴展%%ESC%%%ESC%
第 1 階段的第二輪(由第 6 階段發起)擴展%ESC%^

這完全不切實際,尤其是當您不知道內容是什麼時。

將任何值可靠地傳遞到 CALLed 例程中的唯一明智策略是按引用傳遞。傳遞包含字串值的變數的名稱,並使用延遲擴展在子例程中擴展該值。

@echo off
setlocal enableDelayedExpansion
set "val=with&ampersand"
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^^&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 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&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

輸出:

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

相關內容