Сохранить переменную после endlocal в пакетном режиме

У меня есть структура папок, например, C:\Temp\, и есть много папок и файлов, и в каждой папке есть «callme.bat». Я хотел бы создать так называемый main.bat, который один за другим вызывает файлы callme в главном окне. Но есть проблема, в файлах callme есть эхо, которое содержит "!" отметьте, что создает проблему для меня.

Я понял проблему с комбинацией setlocal-endlocal, потому что пакетный скрипт хочет интерпретировать сообщение внутри "!" отметки, поэтому я должен использовать endlocal, но если бы я это сделал, я бы не смог запустить callme bats.

callme.bat

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

main.bat вариант 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 вариант 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 вариант 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

Поэтому я не знаю, что делать. У кого-нибудь есть идея?

вывод варианта 1:

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

выход варианта 2-3:

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

person Gregori    schedule 21.06.2019    source источник
comment
Пожалуйста, не переопределяйте %PATH%, это очень важная системная переменная, меняйте ее имя в каждом из ваших .bat файлов.   -  person Compo    schedule 21.06.2019
comment
Вам не нужно использовать отложенное расширение или даже Set. Однострочный скрипт должен работать нормально, @For /F "Delims=" %%A In ('Dir /B/AD "C:\Temp" 2^>NUL')Do @Call "%%~fA\callme.bat" 2>NUL или, альтернативно, @For /D %%A In ("C:\Temp\*")Do @Call "%%~fA\callme.bat" 2>NUL.   -  person Compo    schedule 21.06.2019


Ответы (2)


Некоторые моменты о вашем коде:

  1. Никогда не используйте PATH в качестве имени переменной, так как это уничтожает переменную PATH для поиска исполняемых файлов.

  2. Используйте расширенный синтаксис SET set "varname=content", чтобы избежать проблем с пробелами для обучения.

  3. Вам нужно только отключить режим отложенного расширения с помощью 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
person jeb    schedule 21.06.2019

TL;DR

ENDLOCAL&set "varname=%sourcevarname%"

возможно, где varname — это имя переменной, которое нужно установить, а sourcevarname — это переменная, значение которой должно быть присвоено varname, и они МОГУТ иметь одно и то же имя, даже если оператор выглядит логически пустым — это экспорт переменной изнутри блока setlocal/endlocal.

Ключевой момент: ДОЛЖЕН быть на одной физической строке и может повторяться при необходимости (т.е.

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

So

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

вполне допустимо, чтобы установить значение fred вне скобки setlocal/endlocal в его конечное значение внутри и billoutside в конечное значение george внутри.

person Magoo    schedule 21.06.2019