Why doesnt %P1% run if it is inside the FOR in () DO?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
nnnmmm
Posts: 141
Joined: 26 Aug 2017 06:11

Why doesnt %P1% run if it is inside the FOR in () DO?

#1 Post by nnnmmm » 26 Aug 2017 09:43

Code: Select all

CCC.BAT is like below
ECHO OFF
SET P1=A1.EXE
SET P2=A2.EXE
SET P3=A3.EXE

SET GG=1 2 3
FOR %%U IN (%GG%) DO (
   %%P%%U%%
)
-------------------
CCC.BAT gives
%P1%
%P2%
%P3%

but it doesnt run and echo doesnt show
A1.EXE
A2.EXE
A3.EXE


How can i make it run A1.EXE A2.EXE A3.EXE

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#2 Post by aGerman » 26 Aug 2017 09:55

You try to expand a nested variable where there are basically 2 possibilities to do so
1) double the outer percent signs (as you already did) and use CALL

Code: Select all

call %%P%%U%%

2) use the delayed variable expansion

Code: Select all

setlocal EnableDelayedExpansion
...
!P%%U!

Note that the programs will be executed synchronously in both cases. That is, the next program won't be run before the previous program was terminated.

Steffen

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#3 Post by dbenham » 26 Aug 2017 10:22

Both of Steffen's solutions work as long as the macros (commands stored within Pn) are simple. But if you want to store arbitrarily complex commands within a variable, and then execute that code by reference, then you need to use a CALLed subroutine.

Note how I use FOR /L instead of FOR to access a range of numbers

Code: Select all

@echo off
setlocal

set "P1=cls"
set "P2=dir *.exe"
set "P3=echo OK&echo Hello world|findstr ."
set "P4=echo The end!"

for /l %%N in (1 1 4) do call :runMacro P%%N
exit /b


:runMacro  macroName
setlocal enableDelayedExpansion
set "macro=!%1!"
endlocal&%macro%
exit /b


Dave Benham

nnnmmm
Posts: 141
Joined: 26 Aug 2017 06:11

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#4 Post by nnnmmm » 26 Aug 2017 12:09

Code: Select all

what is the difference between set "P1=cls" and SET P1=CLS (LET P1$="CLS" in basic compiler)
what would be the closest form of SET "P1=cls" in a Basic compiler?

ENDLOCAL & %MACRO% works.
But why doesnt this work like below? what is endlocal telling to & ("interpret the next line indicator")?
ENDLOCAL
%MACRO%

without EXIT /b,  a batch still works but slow why?

@ECHO OFF
SETLOCAL
a batch still works with setlocal, it must have been the same as SETLOCAL disableDELAYEDEXPANSION?

sorry i had to break it down to understand them

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#5 Post by aGerman » 26 Aug 2017 13:36

nnnmmm wrote:what is the difference between set "P1=cls" and SET P1=CLS (LET P1$="CLS" in basic compiler)

Having the assignment itself in quotation marks prevents you from having side effects with special characters (like &<>|).

nnnmmm wrote:what would be the closest form of SET "P1=cls" in a Basic compiler?

I don't think there are different kinds of assignments in Basic. Besides of that I don't understand why you believe you could "translate" everything from Batch to Basic or vice versa. FWIW What Basic dialect are you referring to?

nnnmmm wrote:ENDLOCAL & %MACRO% works.
But why doesnt this work like below? what is endlocal telling to & ("interpret the next line indicator")?
ENDLOCAL
%MACRO%

ENDLOCAL quits a sub-environment that was created by SETLOCAL. If you want to preserve a value that was changed in the subenvironment you have to do that either in the same line or an prenthese block. The & is just for command concatenation.

nnnmmm wrote:without EXIT /b, a batch still works but slow why?

Never noticed an effect like that.


nnnmmm wrote:a batch still works with setlocal, it must have been the same as SETLOCAL disableDELAYEDEXPANSION?

Not necessarily. You might have set delayed variable expansion as default in your registry.

Steffen

nnnmmm
Posts: 141
Joined: 26 Aug 2017 06:11

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#6 Post by nnnmmm » 27 Aug 2017 00:17

>Having the assignment itself in quotation marks prevents you from having side effects with >special characters (like &<>|). what would be the closest form of SET "P1=cls" in a Basic compiler?

so is it ok, if there arent any side effects detected?,
i will just replace SET "A=B" with SET A=B for the time being.
SET A=B means, A comes B, or A takes the value B, but its value was maybe something different before. so the old value of A is gone.

SET "A=B" is the same thing as SET A=B, but you cant use SET A=B & SET DD=E in the same line, kind of things.

>why you believe you could "translate" everything from Batch to Basic or vice versa. FWIW What >Basic dialect are you referring to?
because a basic lingo is very easy, just about anyone can learn it in a couple of hours or so.
i dont mean to know the exact translation, but just something similar form maybe as to how variables move, batch scripts are so difficult to read, they seem to squeeze everything in one line, and lacking with using (), it is hard to tell which one has the 1st priority

i use True basic, and i can ONLY read GW basic, fortran, and pascal
basic and fortran are nearly the same. they even have a simple converter between them.

i dont mean like a visual basic or any object oriented compliers, no.

pieh-ejdsch
Posts: 240
Joined: 04 Mar 2014 11:14
Location: germany

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#7 Post by pieh-ejdsch » 27 Aug 2017 04:22

Hellol,

Batch rules:
A batch viewed as a single command line:
1. An instruction
- set, dir, find, [...]
- if, for, cmd
2. Chained commands & | && || - as point 1 or 3
3. In parentheses: command/lines - as point 1 or 2

Wherein:
1. A single line is read to the end of the line and executed according to the rules "of the command interpreter" immediately after the import.
2. Concatenations are defined as single program parts simultaneously "|" Or successively "& && ||" started. Then treat as point 1.
2. Commands, which are summarized in brackets, are read as line-by-line as a separate program and then passed to the command interpreter (CLI) as one or more lines in the batch.
This part is scrambled line by line like a written and after-averaging batch according to point 1 and point 2.

A variables enclosed in percentages show the content at the time of the first reading of a command line.
B variables included in exclamation marks (use "setlocal enabledelayedexpansion") show the content at the last processing time according to point 1.
C Numeric set statements handle the content (without percentage or exclamation point in the variable name) at the time of the calculation according to the calculation rules. Wherein A or B can also be used to calculate (but behave as A or B).

You can reset a variable at any time of the execution (which runs line by line or after point 1).
However, this is treated according to the aspect A or B or C and processed accordingly.

Each variable can be placed in a for-loop (after all points) into a run variable (use "endlocal" or setlocal "disable delayedexpansion"). Then can be set to Other variables as desired.

PS
you can set from a to b and b to a:

Code: Select all

(
set "B=%a%"
set "A=%b%"
)

see: this and that
Phil

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#8 Post by aGerman » 27 Aug 2017 05:26

nnnmmm wrote:so is it ok, if there arent any side effects detected?,
i will just replace SET "A=B" with SET A=B for the time being.

The syntax with quotation marks is just best practice.


nnnmmm wrote:SET A=B means, A comes B, or A takes the value B, but its value was maybe something different before. so the old value of A is gone.

A is a variable name, B is a value (string). If B is also a variable and you want to assign it's value to A you have to expand this value using percent signs (%B%). And yes if A was defined with another value before than it will be overwritten.


nnnmmm wrote:SET "A=B" is the same thing as SET A=B, but you cant use SET A=B & SET DD=E in the same line, kind of things.

You can just do that (but be careful, the space between B and & belongs to the value because you didn't use quotation marks). You only can't access a variable value set in the same line without enabling delayed expansion.


nnnmmm wrote:because a basic lingo is very easy, just about anyone can learn it in a couple of hours or so.

I disagree. It's just you believe it's easier because you are already familiar with Basic. Batch isn't more complicated. Only the syntax is new to you.


nnnmmm wrote:i dont mean to know the exact translation, but just something similar form

Batch isn't comparable with any other language that I know (including Basic dialects). That means if you want to learn Batch then just do it but quit comparing it with Basic. You will need to use other techniques and algorithms to achieve a certain task. (And sometimes you will not even be able to do things that you know from other languages.)

Steffen

nnnmmm
Posts: 141
Joined: 26 Aug 2017 06:11

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#9 Post by nnnmmm » 27 Aug 2017 06:04

Code: Select all

@ECHO OFF
SETLOCAL

SET P1=DIR *.MP3
SET P2=DIR *.BAT
SET P3=DIR *.PNG
SET P4=DIR *.TXT

SetLocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

SET    U=9
SET /P U=INPUT 1 2 3 4:

SET CC=0
FOR /L %%N IN (1 1 4) DO (
    SET /A CC=!CC!+1 

    IF !CC! EQU %U% (

      IF /I !CC!==1 ECHO 111111
      IF /I !CC!==2 CALL :RUNMACRO1 %%N P%%N
      IF /I !CC!==3 CALL :RUNMACRO3 P%%N
      IF /I !CC!==4 CALL :RUNMACRO4 P%%N
      PAUSE
   )
)
EXIT /B

:RUNMACRO1  MACRONAME1
   @ECHO OFF
   SETLOCAL ENABLEDELAYEDEXPANSION
   SET MACRO1=!%1!
   SET MACRO2=!%2!
   ECHO %MACRO1% %MACRO2%
   ENDLOCAL&ECHO %MACRO1% %MACRO2%
EXIT /B

:RUNMACRO3  MACRONAME3
   @ECHO OFF
   SETLOCAL ENABLEDELAYEDEXPANSION
   SET MACRO3=!%1!
   ENDLOCAL&%MACRO3%
EXIT /B

:RUNMACRO4  MACRONAME4
   @ECHO OFF
   SETLOCAL ENABLEDELAYEDEXPANSION
   SET MACRO4=!%1!
   ENDLOCAL&ECHO %MACRO4%
   ENDLOCAL&%MACRO4%
EXIT /B


i think input number 2 and 4 dont work.
and i can not display the order number, display the string and run the string related to the command, what to do all at the same time for the selection.

you can put some life into the script, but please spread them with ()'s and less packing a lot into one line,
so i can do more customizations
thanks
Last edited by nnnmmm on 27 Aug 2017 06:30, edited 3 times in total.

nnnmmm
Posts: 141
Joined: 26 Aug 2017 06:11

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#10 Post by nnnmmm » 27 Aug 2017 06:22

deleted, since the code is too naive and long
Last edited by nnnmmm on 28 Aug 2017 05:11, edited 1 time in total.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#11 Post by aGerman » 27 Aug 2017 08:41

Code: Select all

@echo off &setlocal

:: assign command lines to variables of an associative array
set "cmmd1=dir *.mp3"
set "cmmd2=dir *.bat"
set "cmmd3=dir *.png"
set "cmmd4=dir *.txt"

:: display all variables that begin with cmmd
set cmmd

:: prompt the user for input and check it's validity
set "input="
set /p "input=Enter a number 1...4: "
if not defined input exit /b
if %input% lss 1 exit /b
if %input% gtr 4 exit /b

:: call a subroutine and pass the entered number
call :execute_command %input%

pause
exit /b

:execute_command
setlocal EnableDelayedExpansion
echo Command #%~1 chosen that is, !cmmd%~1!
set "macro=!cmmd%1!"
endlocal&%macro%
exit /b


I don't understand your 2nd code. Too many badly chosen variable names without context to their meaning.

Steffen

nnnmmm
Posts: 141
Joined: 26 Aug 2017 06:11

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#12 Post by nnnmmm » 29 Aug 2017 05:54

Code: Select all

@ECHO OFF

SET CMMDA=DIR /B *.MP3
SET CMMDF=DIR /B *.BAT
SET CMMDH=DIR /B *.PNG
SET CMMDZ=DIR /B *.TXT

FOR %%N IN (A F H Z) DO (
   CALL :RUNMACRO1 %%N
)

ECHO.
SET /P INPUT=A F H Z :
ECHO.

CALL :RUNMACRO2 %INPUT%

GOTO END

:RUNMACRO1

   SetLocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
   SET NUM=%1
   ECHO !NUM!.  !CMMD%~1!

EXIT /B


:RUNMACRO2
   
   SetLocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
   SET P1=!CMMD%1!
   %P1%

EXIT /B

:END
ECHO.
ECHO DONE



beautifully done, now i can read the script and with the max customization i needed.

I got rid of this dreadful line endlocal&%macro%
i thought that endlocal% was the only way i could use the command with call functions. why didnt i need the line endlocal% in my script? but big thanks, i couldnt have done it without your help.
the next i need to know how to pass 2 variables for the call functions. i will do that in a different post. and i might have to loop it around the whole main menu so that i could keep running the commands instead of exiting the script.. thanks much

endlocal&echo %macro%
endlocal&%macro%
endlocal%dir
.
.
.
etc


ENABLEDELAYEDEXPANSION was my LAST resort for doing any batches at my level,
this one ruins the data with "!" in it so badly.
Last edited by nnnmmm on 29 Aug 2017 17:35, edited 1 time in total.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Why doesnt %P1% run if it is inside the FOR in () DO?

#13 Post by aGerman » 29 Aug 2017 10:20

Please read
When to use ! In batch

You should toggle delayed expansion depending on what you're trying to do. If you want to assign a variable then work with delayed expansion disabled. If you want to work with the variable value then enable it.

Steffen

Post Reply