4

so i have in a batch-file some vars stored from a text file

(
set /p var1=
set /p var2=
set /p var3=
)<oi.txt

and they represent an if statement.

if i were to run %var1% it would run the if statement, however when i run

for /l %%i in (1,1,3) do !var%%i!

(in setlocal enabledelayedexpansion) it runs the if, however it returns

`if` is not recognized as an internal or external command
`if` is not recognized as an internal or external command
`if` is not recognized as an internal or external command

is it a microsoft oversight? or maybe something that fixes another bug at the price of not having this option?

*edit this has nothing to do with the for command, using !var%number%! with var1 having the if statement inside, returns the same problem. (also, im 100% sure the if statement inside the var is correct, why wouldnt it be recognized even if it was wrong?)

Jonhyfun
  • 37
  • 4
  • 2
    so you have some commands in `oi.txt`? What are they? – npocmaka Jul 13 '17 at 09:06
  • 1
    @npocmaka It seems that the problem comes down to why `set "var=echo hi"` followed by `!var!` works but `set "var=if 1 equ 1 echo true"` followed by `!var!` doesn't and produces an `'if' is not recognized as...` error message instead. – 303 Jul 13 '17 at 15:37
  • 2
    Please post the content of `oi.txt`! Anyway, the commands `if` and `for` (and `rem`) are handled specially by the command interpreter, they are recognised *before* delayed expansion is processed, that is why this error occurs; reference this thread: [How does the Windows Command Interpreter (CMD.EXE) parse scripts?](https://stackoverflow.com/q/4094699) – aschipfl Jul 13 '17 at 16:15

1 Answers1

3

When you execute commands that are stored within an environment variable, that is frequently called a macro. Very complicated macros can be created and executed by using %macro%. But execution of !macro! via delayed expansion is severely crippled - there are many restrictions.

The cmd.exe command (and batch) parser is a complicated beast. I'm not aware of any official documentation that would explain the behavior.

But there are a set of parsing phase rules developed by jeb that help explain why delayed expansion macro execution does not work with IF or FOR statements.

Both IF and FOR require special parsing that occurs in phase 2. But delayed expansion does not occur until phase 5. So the required IF and FOR parsing never occurs when you try to execute commands via delayed expansion.

There is no work around. If you want to include FOR or IF within an environment variable "macro", then you must execute the macro with normal %macro% expansion.

The explanation is basically the same as to why you cannot use delayed expansion for FOR or IF options or flags.

Here is an IF example:

@echo off
setlocal enableDelayedExpansion
set "ifFlag=/I"

:: This works
if %ifFlag% a==A echo match

:: This does not work
if !ifFlag! a==A echo match

And here is a FOR example:

@echo off
setlocal enableDelayedExpansion
set "forOptions=delims=: tokens=1,2"

:: This works
for /f "%forOptions%" %%A in ("1:2") do echo A=%%A  B=%%B

:: This does NOT works
for /f "!forOptions!" %%A in ("1:2") do echo A=%%A  B=%%B
dbenham
  • 119,153
  • 25
  • 226
  • 353
  • thank you, very great info on parsing... ill just add %var1% %var2%.... by hand or maybe put all that in a text file – Jonhyfun Jul 13 '17 at 20:22
  • 1
    The phase rules also explain why the `rem`, `if`, and `for` commands cannot be exectuted by for-loop variable expansion. When `var#` expands to any of those commands, the following wont work either: `for /f "tokens=1,* delims==" %%i in ('set var') do %%j` By the time that `%%j` has been expanded in phase 4, phase 2 has already ended and the parser no longer scans for `rem`, `if`, and `for` commands. – 303 Jul 13 '17 at 23:06
  • @treintje - I didn't want to muddy the waters, but you are absolutely correct. – dbenham Jul 13 '17 at 23:08