Search code examples
windowsbatch-filecmddelayedvariableexpansion

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.

Solution

  • 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