为什么 IF 检查忽略检查表达式后的“^<delimter>some_word”?
Why IF checking ignores "^<delimter>some_word" after the check expression?
示例如下:
@echo off
:: check syntax ignores "^<delimiter>something" right after check expression
if defined path^ blah echo #
if exist c:\^ blah echo #
if errorlevel 0^ blah echo #
:: but in comparison operations escaping works well
if 1^ blah==1^ blah echo #
因为这就是它的工作原理 ;-)
我认为这是 IF 命令的设计缺陷。 IF命令有复杂的(多阶段)解析规则,我认为微软有点失误。
转义不适用于 IF EXIST 或 IF DEFINED。第一次解析通过正确识别条件和命令,但实际比较停止在第一个白色 space.
引号适用于 IF EXIST。但是引号对 IF DEFINED 没有帮助,因为它们被认为是变量名称的一部分。
让它在所有情况下都能正常工作的唯一方法是使用 FOR 变量或延迟扩展:
@echo off
setlocal enableDelayedExpansion
set "var=%%%%~A"
:: Start with a clean slate
set "a="
set "a z="
del "a" "a z" 2>nul
:: ---------- test escape --------------
:: This fails
set "a z=1"
if defined a^ z (
echo if defined a^^ z TRUE = SUCCESS
) else (
echo if defined a^^ z FALSE = FAILURE
)
set "a z="
:: This fails
copy nul "a z" >nul
if exist a^ z (
echo if exist a^^ z TRUE = SUCCESS
) else (
echo if exist a^^ z FALSE = FAILURE
)
del "a z"
:: This fails (looks at the wrong variable)
set "a=1"
if defined a^ z (
echo if defined a^^ z TRUE = FAILURE
) else (
echo if defined a^^ z FALSE = SUCCESS
)
set "a="
:: This fails (looks at wrong file)
copy nul "a" >nul
if exist a^ z (
echo if exist a^^ z TRUE = FAILURE
) else (
echo if exist a^^ z FALSE = SUCCESS
)
del "a"
echo(
:: ---------- test quotes --------------
:: This fails
set "a z=1"
if defined "a z" (
echo if defined "a z" TRUE = SUCCESS
) else (
echo if defined "a z" FALSE = FAILURE
)
set "a z="
:: This succeeds
copy nul "a z" >nul
if exist "a z" (
echo if exist "a z" TRUE = SUCCESS
) else (
echo if exist "a z" FALSE = FAILURE
)
del "a z"
:: This fails (looks at the wrong variable with quotes in name)
set ""a z"=1"
if defined "a z" (
echo if defined "a z" TRUE = FAILURE
) else (
echo if defined "a z" FALSE = SUCCESS
)
set ""a z"="
:: This succeeds
copy nul "a" >nul
if exist "a z" (
echo if exist "a z" TRUE = FAILURE
) else (
echo if exist "a z" FALSE = SUCCESS
)
del "a"
echo(
:: ---------- test FOR variable --------------
:: This succeeds
set "a z=1"
for %%A in ("a z") do if defined %%~A (
echo if defined !var! TRUE = SUCCESS
) else (
echo if defined !var! FALSE = FAILURE
)
set "a z="
:: This succeeds
copy nul "a z" >nul
for %%A in ("a z") do if exist %%~A (
echo if exist !var! TRUE = SUCCESS
) else (
echo if exist !var! FALSE = FAILURE
)
del "a z"
:: This succeeds
set "a=1"
for %%A in ("a z") do if defined %%~A (
echo if defined !var! TRUE = FAILURE
) else (
echo if defined !var! FALSE = SUCCESS
)
set "a="
:: This succeeds
copy nul "a" >nul
for %%A in ("a z") do if exist %%~A (
echo if exist !var! TRUE = FAILURE
) else (
echo if exist !var! FALSE = SUCCESS
)
del "a"
echo(
:: ---------- test delayed expansion --------------
set "var=a z"
:: This succeeds
set "a z=1"
if defined !var! (
echo if defined ^^!var^^! TRUE = SUCCESS
) else (
echo if defined ^^!var^^! FALSE = FAILURE
)
set "a z="
:: This succeeds
copy nul "a z" >nul
if exist !var! (
echo if exist ^^!var^^! TRUE = SUCCESS
) else (
echo if exist ^^!var^^! FALSE = FAILURE
)
del "a z"
:: This succeeds
set "a=1"
if defined !var! (
echo if defined ^^!var^^! TRUE = FAILURE
) else (
echo if defined ^^!var^^! FALSE = SUCCESS
)
set "a="
:: This succeeds
copy nul "a" >nul
if exist !var! (
echo if exist ^^!var^^! TRUE = FAILURE
) else (
echo if exist ^^!var^^! FALSE = SUCCESS
)
del "a"
--输出--
if defined a^ z FALSE = FAILURE
if exist a^ z FALSE = FAILURE
if defined a^ z TRUE = FAILURE
if exist a^ z TRUE = FAILURE
if defined "a z" FALSE = FAILURE
if exist "a z" TRUE = SUCCESS
if defined "a z" TRUE = FAILURE
if exist "a z" FALSE = SUCCESS
if defined %%~A TRUE = SUCCESS
if exist %%~A TRUE = SUCCESS
if defined %%~A FALSE = SUCCESS
if exist %%~A FALSE = SUCCESS
if defined !var! TRUE = SUCCESS
if exist !var! TRUE = SUCCESS
if defined !var! FALSE = SUCCESS
if exist !var! FALSE = SUCCESS
为什么?
我不知道。
但在这种情况下,分词器似乎执行了两次。
这里是一个例子,表明分词器独立于 ECHO ON
的中间输出
echo ON
setlocal EnableDelayedExpansion
set "var=hello you"
if !var! == hello^ you echo true
if !var! == hello you echo true
两行都显示为 if !var! == hello you echo true
,但只有第一行执行 echo true
,因为 hello you
是一个标记,但第二个示例中没有。
set var=1
IF defined var^ bang echo VAR is defined
但正如 dbenham 解释的那样,IF DEFINED
和 If EXIST
似乎按预期首先将其标记化,因为第二个词不会用作命令,但它已完全删除。
有趣的是 FOR 参数和延迟扩展不受影响,尽管这些阶段直接跟在 回声阶段。
所以我假设,与 IF .. <compare>
相比,IF defined
和 IF EXIST
使用了另一个分词器。
使用 ECHO ON
(如 JosefZ 所述)您可以看到差异。
if !var! == hello^ you echo true
if defined hello^ you echo is defined
输出
C:\temp>if !var! == hello you echo true
C:\temp>if defined hello echo is defined
在第一个例子中 hello you
是完整的,但在第二个例子中 you
被删除了。
示例如下:
@echo off
:: check syntax ignores "^<delimiter>something" right after check expression
if defined path^ blah echo #
if exist c:\^ blah echo #
if errorlevel 0^ blah echo #
:: but in comparison operations escaping works well
if 1^ blah==1^ blah echo #
因为这就是它的工作原理 ;-)
我认为这是 IF 命令的设计缺陷。 IF命令有复杂的(多阶段)解析规则,我认为微软有点失误。
转义不适用于 IF EXIST 或 IF DEFINED。第一次解析通过正确识别条件和命令,但实际比较停止在第一个白色 space.
引号适用于 IF EXIST。但是引号对 IF DEFINED 没有帮助,因为它们被认为是变量名称的一部分。
让它在所有情况下都能正常工作的唯一方法是使用 FOR 变量或延迟扩展:
@echo off
setlocal enableDelayedExpansion
set "var=%%%%~A"
:: Start with a clean slate
set "a="
set "a z="
del "a" "a z" 2>nul
:: ---------- test escape --------------
:: This fails
set "a z=1"
if defined a^ z (
echo if defined a^^ z TRUE = SUCCESS
) else (
echo if defined a^^ z FALSE = FAILURE
)
set "a z="
:: This fails
copy nul "a z" >nul
if exist a^ z (
echo if exist a^^ z TRUE = SUCCESS
) else (
echo if exist a^^ z FALSE = FAILURE
)
del "a z"
:: This fails (looks at the wrong variable)
set "a=1"
if defined a^ z (
echo if defined a^^ z TRUE = FAILURE
) else (
echo if defined a^^ z FALSE = SUCCESS
)
set "a="
:: This fails (looks at wrong file)
copy nul "a" >nul
if exist a^ z (
echo if exist a^^ z TRUE = FAILURE
) else (
echo if exist a^^ z FALSE = SUCCESS
)
del "a"
echo(
:: ---------- test quotes --------------
:: This fails
set "a z=1"
if defined "a z" (
echo if defined "a z" TRUE = SUCCESS
) else (
echo if defined "a z" FALSE = FAILURE
)
set "a z="
:: This succeeds
copy nul "a z" >nul
if exist "a z" (
echo if exist "a z" TRUE = SUCCESS
) else (
echo if exist "a z" FALSE = FAILURE
)
del "a z"
:: This fails (looks at the wrong variable with quotes in name)
set ""a z"=1"
if defined "a z" (
echo if defined "a z" TRUE = FAILURE
) else (
echo if defined "a z" FALSE = SUCCESS
)
set ""a z"="
:: This succeeds
copy nul "a" >nul
if exist "a z" (
echo if exist "a z" TRUE = FAILURE
) else (
echo if exist "a z" FALSE = SUCCESS
)
del "a"
echo(
:: ---------- test FOR variable --------------
:: This succeeds
set "a z=1"
for %%A in ("a z") do if defined %%~A (
echo if defined !var! TRUE = SUCCESS
) else (
echo if defined !var! FALSE = FAILURE
)
set "a z="
:: This succeeds
copy nul "a z" >nul
for %%A in ("a z") do if exist %%~A (
echo if exist !var! TRUE = SUCCESS
) else (
echo if exist !var! FALSE = FAILURE
)
del "a z"
:: This succeeds
set "a=1"
for %%A in ("a z") do if defined %%~A (
echo if defined !var! TRUE = FAILURE
) else (
echo if defined !var! FALSE = SUCCESS
)
set "a="
:: This succeeds
copy nul "a" >nul
for %%A in ("a z") do if exist %%~A (
echo if exist !var! TRUE = FAILURE
) else (
echo if exist !var! FALSE = SUCCESS
)
del "a"
echo(
:: ---------- test delayed expansion --------------
set "var=a z"
:: This succeeds
set "a z=1"
if defined !var! (
echo if defined ^^!var^^! TRUE = SUCCESS
) else (
echo if defined ^^!var^^! FALSE = FAILURE
)
set "a z="
:: This succeeds
copy nul "a z" >nul
if exist !var! (
echo if exist ^^!var^^! TRUE = SUCCESS
) else (
echo if exist ^^!var^^! FALSE = FAILURE
)
del "a z"
:: This succeeds
set "a=1"
if defined !var! (
echo if defined ^^!var^^! TRUE = FAILURE
) else (
echo if defined ^^!var^^! FALSE = SUCCESS
)
set "a="
:: This succeeds
copy nul "a" >nul
if exist !var! (
echo if exist ^^!var^^! TRUE = FAILURE
) else (
echo if exist ^^!var^^! FALSE = SUCCESS
)
del "a"
--输出--
if defined a^ z FALSE = FAILURE
if exist a^ z FALSE = FAILURE
if defined a^ z TRUE = FAILURE
if exist a^ z TRUE = FAILURE
if defined "a z" FALSE = FAILURE
if exist "a z" TRUE = SUCCESS
if defined "a z" TRUE = FAILURE
if exist "a z" FALSE = SUCCESS
if defined %%~A TRUE = SUCCESS
if exist %%~A TRUE = SUCCESS
if defined %%~A FALSE = SUCCESS
if exist %%~A FALSE = SUCCESS
if defined !var! TRUE = SUCCESS
if exist !var! TRUE = SUCCESS
if defined !var! FALSE = SUCCESS
if exist !var! FALSE = SUCCESS
为什么?
我不知道。
但在这种情况下,分词器似乎执行了两次。
这里是一个例子,表明分词器独立于 ECHO ON
echo ON
setlocal EnableDelayedExpansion
set "var=hello you"
if !var! == hello^ you echo true
if !var! == hello you echo true
两行都显示为 if !var! == hello you echo true
,但只有第一行执行 echo true
,因为 hello you
是一个标记,但第二个示例中没有。
set var=1
IF defined var^ bang echo VAR is defined
但正如 dbenham 解释的那样,IF DEFINED
和 If EXIST
似乎按预期首先将其标记化,因为第二个词不会用作命令,但它已完全删除。
有趣的是 FOR 参数和延迟扩展不受影响,尽管这些阶段直接跟在 回声阶段。
所以我假设,与 IF .. <compare>
相比,IF defined
和 IF EXIST
使用了另一个分词器。
使用 ECHO ON
(如 JosefZ 所述)您可以看到差异。
if !var! == hello^ you echo true
if defined hello^ you echo is defined
输出
C:\temp>if !var! == hello you echo true
C:\temp>if defined hello echo is defined
在第一个例子中 hello you
是完整的,但在第二个例子中 you
被删除了。