为什么IF检查会忽略&#34; ^ <delimiter> some_word n#34;检查表达式后?</delimter>

时间:2015-01-17 13:57:51

标签: batch-file if-statement cmd

以下是示例:

@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 #

2 个答案:

答案 0 :(得分:6)

因为它是如何运作的; - )

在我看来,这是IF命令的设计缺陷。 IF命令有复杂的(多阶段)解析规则,我认为MicroSoft稍稍放弃了这个规则。

Escape不适用于IF EXIST或IF DEFINED。第一个解析过程正确识别条件和命令,但实际比较在第一个空格处停止。

引用与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

答案 1 :(得分:3)

为什么?
我不知道。

但似乎在这种情况下,tokenizer会执行两次。

这是一个示例,表明令牌化器独立于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 DEFINEDIf EXIST似乎首先按预期将其标记,因为第二个单词不会被用作命令,但它会被完全删除。

相反的效果是FOR参数和延迟扩展不受影响,尽管这些阶段直接跟随回声阶段

所以我假设,与IF defined相比,IF EXISTIF .. <compare>使用了另一个标记器。

使用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已被删除。