Назад | Перейти на главную страницу

Потому что в пакете имеет странное поведение при чтении папок

Я пытаюсь сделать простой пакет (это еще не все, но это та часть, которая заставляет все терпеть неудачу)

@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