2016-09-22 51 views
6

當啓用delayed expansion時,通常需要正確地轉義感嘆號才能獲得文字(如^^!"",^!,以獲得文字!)。爲什麼在`for/F`或`for/R`參數中不需要跳過感嘆號?

但是,爲什麼在/Rfor循環命令的開關後立即提供的參數中不必轉義所需的感嘆號?


考慮到上述轉義規則,我創建使用for /R以下批處理腳本,並作爲參數在其名稱中!一個目錄(/R選項後面說明):

@echo off 
setlocal EnableExtensions EnableDelayedExpansion 

set "TARGET=excl^!dir" 
set "FILE=empty_%RANDOM%.txt" 
echo/ 
echo creating directory: !TARGET! 
mkdir "!TARGET!" 
echo placing empty file: !TARGET!\%FILE% 
> "!TARGET!\%FILE%" break 
echo/ 
echo adequately escaped `^^!`: 
for /R "excl^!dir" %%F in ("*.*") do echo(found item: %%~nxF 
for /R excl^^!dir %%F in ("*.*") do echo(found item: %%~nxF 
echo/ 
echo improperly escaped `^^!`: 
for /R "excl!dir" %%F in ("*.*") do echo(found item: %%~nxF 
for /R excl!dir %%F in ("*.*") do echo(found item: %%~nxF 
for /R excl^!dir %%F in ("*.*") do echo(found item: %%~nxF 

erase "!TARGET!\%FILE%" 
rmdir "!TARGET!" 

endlocal 
exit /B 

令人驚訝的是,該目錄僅列舉了而沒有轉義了!。這是一個輸出:

creating directory: excl!dir 
placing empty file: excl!dir\empty_18378.txt 

adequately escaped `!`: 

improperly escaped `!`: 
found item: empty_18378.txt 
found item: empty_18378.txt 
found item: empty_18378.txt 

我期待目錄的情況下,可以列舉感嘆號其實正確轉義,否則不會;但結果顯示出相反的行爲。


類似的現象出現與for /F,像下面的腳本,在選項字符串的!

@echo off 
setlocal EnableExtensions EnableDelayedExpansion 

set "STRING=EXCLAMATION ^! MARK AND CARET ^^ SYMBOL" 
echo/ 
echo normal expansion: %STRING% 
echo delayed expansion: !STRING! 
echo/ 
echo adequately escaped `^^!`: 
for /F "tokens=1-2 delims=^!" %%K in ("!STRING!") do echo(%%K -- %%L 
for /F tokens^=1-2^ delims^=^^! %%K in ("!STRING!") do echo(%%K -- %%L 
echo/ 
echo improperly escaped `^^!`: 
for /F "tokens=1-2 delims=!" %%K in ("!STRING!") do echo(%%K -- %%L 
for /F tokens^=1-2^ delims^=! %%K in ("!STRING!") do echo(%%K -- %%L 
for /F tokens^=1-2^ delims^=^! %%K in ("!STRING!") do echo(%%K -- %%L 

endlocal 
exit /B 

輸出看起來是這樣的,奇怪:

normal expansion: EXCLAMATION MARK AND CARET SYMBOL 
delayed expansion: EXCLAMATION ! MARK AND CARET^SYMBOL 

adequately escaped `!`: 
EXCLAMATION -- MARK AND CARET 
EXCLAMATION -- MARK AND CARET 

improperly escaped `!`: 
EXCLAMATION -- MARK AND CARET^SYMBOL 
EXCLAMATION -- MARK AND CARET^SYMBOL 
EXCLAMATION -- MARK AND CARET^SYMBOL 

在這裏,我期望整個字符串被拆分我正好兩個令牌:EXCLAMATIONMARK AND CARET^SYMBOL。但第二個標記太短,從插入符號^開始的所有內容都缺失;所以我得出這樣的結論:用於逃避!^是從字面上理解的。沒有(或窮人)逃跑,返回的令牌是預期的。

+1

代碼中沒有什麼需要延遲擴展。在一組行中使用延遲擴展,一個邏輯行分割多於一個物理行(如'for'或'if'命令中的多個命令)或一行上的多個命令*當您更改變量的值時在該塊內,並希望在該塊內使用它*。 – 2016-09-22 22:32:05

+1

是的,我知道,@Noodles;這些腳本只是爲了證明這種奇怪的行爲... – aschipfl

回答

6

FOR,IFREM的選項只能分析到特殊字符階段。
或者更好的是在特殊字符階段檢測到命令,然後激活不同的分析器。

因此無法在選項中使用延遲擴展和FOR-Parameter。

這些測試失敗,錯誤

for /F %%O in ("defined") do (
    if %%O var echo yes 
) 

set option=defined 
if !option! var echo yes 

這似乎是工作,但使用了錯誤的分隔符(Deilmsy!

set "myDelims=123" 
for /F "tokens=1,2 delims=!myDelims!" %%A in ("Hello 1 world") do (
    echo Token1=%%A Token2=%%B 
) 

並且對於REM

set "help=/?" 
REM !HELP! - No help will be shown 
+2

+1,左邊的未說是明顯的事實,你逃跑!以防止延期擴張。如果延遲擴展不能用於特定的構造,則沒有任何可逃脫的地方。 – dbenham

+0

謝謝您的洞察!所以我明白使用'for'變量不能用於定義該命令的參數[](http://stackoverflow.com/a/4095133)而'delims'應該包含'D'而不是'd',對? – aschipfl

+1

@aschipfl是的,這同樣適用於'FOR'變量,請參見第一個expamle。另外,你的第二部分是對的,我固定了'D' – jeb