Gregori
Gregori

Reputation: 85

Keep variable after endlocal in Batch

I have a folder structure, which is like for example C:\Temp\ and there are a lot of folder and file, and within each folder there are a "callme.bat". I would like to create a so called main.bat which is one after another call the callme files within the main' window. But there is a problem, within the callme files are some echo which contains "!" mark what make a problem for me.

I realized the problem with the setlocal-endlocal combo, because the batch scrip wants to interpret the message within the "!" marks, so I must use endlocal, but if I did I not able to run the callme bats.

callme.bat

@echo off
echo !!! hidden message !!! not hidden message
pause

main.bat variant 1

@echo off
setlocal enabledelayedexpansion

set PATH=C:\Temp
for /F %%x in ('dir /B/A:D %PATH%') do (
    set CURR_DIR=%PATH%\%%x
    set ACTUAL_BATCH=!CURR_DIR!\callme.bat
    echo !ACTUAL_BATCH!

    call !ACTUAL_BATCH!
    pause
)
pause
exit

main.bat variant 2

@echo off
set PATH=C:\Temp
for /F %%x in ('dir /B/A:D %PATH%') do (
    setlocal enabledelayedexpansion

    set CURR_DIR=%PATH%\%%x
    set ACTUAL_BATCH=!CURR_DIR!\callme.bat
    echo !ACTUAL_BATCH!

    ENDLOCAL & SET VAR=!ACTUAL_BATCH!
    echo %VAR%
    pause
)
pause
exit

main.bat variant 3

@echo off
set PATH=C:\Temp
for /F %%x in ('dir /B/A:D %PATH%') do (
    setlocal enabledelayedexpansion

    set CURR_DIR=%PATH%\%%x
    set ACTUAL_BATCH=!CURR_DIR!\callme.bat
    echo !ACTUAL_BATCH!

    REM source: https://stackoverflow.com/questions/3262287/make-an-environment-variable-survive-endlocal
    for /f "delims=" %%A in (""!ACTUAL_BATCH!"") do endlocal & set "VAR=%%~A"
    echo %VAR%

    call %VAR%
    pause
)
pause
exit

So I don't know what to do. Anyone has an idea?

variant 1's output:

C:\Temp\1\callme.bat
 not hidden message
C:\Temp\2\callme.bat
 not hidden message

variant 2-3's output:

C:\Temp\1\callme.bat
ECHO is off.
C:\Temp\2\callme.bat
ECHO is off.

Upvotes: 2

Views: 1616

Answers (2)

jeb
jeb

Reputation: 82247

Some points about your code:

  1. Never use PATH as a variable name, as it destroys the PATH variable for searching executable files.

  2. Use the extended SET syntax set "varname=content" to avoid problems with trainling spaces.

  3. You only need to disable the delayed expansion mode by using setlocal DisableDelayedExpansion

@echo off
setlocal EnableDelayedExpansion

set MY_PATH=C:\Temp
for /F %%x in ('dir /B/A:D %PATH%') do (
    set "CURR_DIR=%MY_PATH%\%%x"
    set "ACTUAL_BATCH=!CURR_DIR!\callme.bat"

    call :execute ACTUAL_BATCH
    pause
)
pause
exit /b

:execute ACTUAL_BATCH
set "batFile=!%~1!"
echo Calling !batFile!

setlocal DisableDelayedExpansion
call %batFile%
endlocal

exit /b

Upvotes: 2

Magoo
Magoo

Reputation: 79983

TL;DR

ENDLOCAL&set "varname=%sourcevarname%"

probably, where varname is the variablename to set and sourcevarname is the variable whose value is to be assigned to varname - and they CAN be the same name, even if the statement appears logically null - it's exporting the variable from within the setlocal/endlocal block.

Key point: MUST be on one physical line and may be repeated if necessary (ie

 ENDLOCAL&set "varname=%sourcevarname%"&set "varname2=%sourcevarname2%"

So

 ENDLOCAL&set "fred=%fred%"&set "bill=%george%"

is perfectly valid, to set the value of fred outside the setlocal/endlocal bracket to its final value inside and of billoutside to the final value of george inside.

Upvotes: 3

Related Questions