Why can I not get a substring of a delayed expansi

2019-02-12 11:41发布

问题:

Why does string-manipulation work inline in an if statement without using delayed expansion variables - but fails otherwise. For example:

set test=testString
if %test:~0,4%==test echo Success

This works correctly; returning Success. However if I do the following:

setLocal enableDelayedExpansion
set test=testString
if !test:~0,4!==test echo Success

I receive the error - 4!==test was unexpected at this time.

Obviously you can get around this by doing something like set comp=!test:~0,4! then just using the !comp! variable in the if statement.

回答1:

npocmaka correctly diagnosed the problem that the IF command gets its own special parsing phase, and token delimiters within the variable expansion are causing problems.

Substitution also causes a problem:

:: This fails
if !test:String=!==test echo Success

The reason why normal expansion works is because that occurs before the IF parsing, but delayed expansion occurs after IF parsing.

An alternative to using quotes is to escape the problem characters.

:: Both of these work
if !test:~0^,4!==test echo Success
if !test:String^=!==test echo Success


回答2:

,;=<tab> and <space> are delimiters for cmd.exe and in many cases are ignored if they are not in quotes and act like empty space.Probably in this case , is taken as the end of the first operand and IF is surprised that there is not valid comparison operator e.g. this will print yep :

if a   ;==;,,=a echo yep

(but will not work if there's a equal sign in the first part of the operands)

But this will not:

if "a ;" == ";,,=a" echo yep

so to make a valid IF expression when you use comma you need quotes.And this will work

setLocal enableDelayedExpansion
set test=testString
if "!test:~0,4!" == "test" echo Success

Without delayed expansion substitution is made immediately and this will work without quotes:

set test=testString
setlocal disableDelayedExpansion
if %test:~0,4% == test echo Succes
endlocal

For the same reason this will be taken as a wrong syntax expression (see jeb's comment):

set "test="
setlocal disableDelayedExpansion
if %test% == test echo Succes
endlocal

May be is not the complete answer , but should be close.As both echo !test:~0,4! and echo %test:~0,4% will work without quotes stays the question why exactly IF fails - may because IF command uses its own parser

As a conclusion - it's always good to use quotes when you compare strings with IF :

  1. with delayed expansion commas and semicolons will cause troubles.
  2. without delayed expansion undefined variables will cause troubles.