Я пытаюсь сделать простой пакет (это еще не все, но это та часть, которая заставляет все терпеть неудачу)
@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
echo %%G
set fullpath=%%G
set basename=%fullpath:~7%
echo %fullpath%
echo %basename%
)
Этот скрипт должен запускаться отовсюду, отсюда и забавный цикл for. Предполагается, что он просматривает каталог, а затем выполняет какие-то действия.
В этом конкретном каталоге есть еще 3 каталога:bomslenovodb
, cpat
и finance
Ожидаемый результат
e:\tmp\bomslenovodb
e:\tmp\bomslenovodb
bomslenovodb
e:\tmp\cpat
e:\tmp\cpat
cpat
e:\tmp\finance
e:\tmp\finance
finance
Фактический выход
First run
e:\tmp\bomslenovodb
ECHO is off.
ECHO is off.
e:\tmp\bomslenovodb
e:\tmp\cpat
ECHO is off.
ECHO is off.
e:\tmp\cpat
e:\tmp\finance
Second run
ECHO is off.
ECHO is off.
e:\tmp\finance
e:\tmp\bomslenovodb
e:\tmp\finance
ECHO is off.
e:\tmp\bomslenovodb
e:\tmp\cpat
e:\tmp\finance
Third run
ECHO is off.
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
ECHO is off.
e:\tmp\finance
e:\tmp\bomslenovodb
e:\tmp\finance
e:\tmp\finance
Fourth run
e:\tmp\bomslenovodb
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
e:\tmp\finance
e:\tmp\finance
Мне кажется, что set fullpath=%%G
ведет себя не так, как задумано, поэтому значение установлено неправильно.
Я на машине с Windows Server 2008, есть идеи?
Классическая пакетная ошибка :-)
Команда SET работает нормально. Это ваше расширение терпит неудачу.
%VAR%
раскрытие происходит, когда оператор анализируется, и все команды в цикле FOR анализируются одновременно. То же самое верно для любого блока кода в скобках. Итак, значения %fullpath%
и %basename%
постоянны на протяжении всего выполнения цикла FOR - значения, существовавшие до входа в цикл (в данном случае не определены).
Исправление заключается в использовании отложенного раскрытия, которое происходит непосредственно перед выполнением команды. Отложенное расширение должно быть включено с помощью setlocal enableDelayedExpansion
прежде, чем его можно будет использовать. И синтаксис расширения изменится на !VAR!
.
@echo off
setlocal enableDelayedExpansion
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
echo %%G
set fullpath=%%G
set basename=!fullpath:~7!
echo !fullpath!
echo !basename!
)
Но есть еще одна потенциальная проблема. Имена файлов могут содержать !
символ и любые переменные FOR, содержащие !
будет поврежден при расширении, если включено отложенное расширение. Решение состоит в том, чтобы включать и выключать отложенное расширение внутри цикла.
@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
echo %%G
set fullpath=%%G
setlocal enableDelayedExpansion
set basename=!fullpath:~7!
echo !fullpath!
echo !basename!
endlocal
)
Если тебе нужно защитить !
литералы, и вам нужно, чтобы ваши назначения переменных сохранялись на всех итерациях, тогда самое простое, что нужно сделать, - это использовать процедуру CALLed, чтобы вы могли использовать обычное расширение. Просто передайте значение переменной FOR в параметр CALL. Но использование CALL значительно медленнее, чем помещать все напрямую в цикл.
@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do call :proc "%%G"
exit /b
:proc
echo %~1
set "fullpath=%~1"
set "basename=%fullpath:~7%"
echo %fullpath%
echo %basename%
exit /b