Это ожидаемое поведение, поскольку %1
разворачивается при анализе строки, и вся конструкция IF с конечным выражением анализируется за один проход. Таким образом, вы не можете видеть результат SHIFT до тех пор, пока не будет проанализирована новая строка, которая не произойдет до тех пор, пока вы не оставите свой скоброванный блок.
Та же проблема возникает при расширении переменных окружения с использованием %var%
. С переменными окружения вы можете обойти эту проблему, включив замедленное расширение, используя SETLOCAL EnableDelayedExpansion
, а затем используя !var!
. Но нет сопоставимого способа расширения параметров с использованием замедленного расширения.
EDIT 2013-06-21 - Существует не сопоставимый способ, но есть простой способ, относительно медленный.
Вы можете принудительно перенаправить линию, используя CALL и удвоить %
.
@echo off
if "%1"=="/p" (
echo %1
shift
echo "shifted"
call echo %%1
)
EDIT 2016-07-15 code in Vladislav's answer это плохая практика, поскольку это означает, что вы можете вернуться назад в пределах блока кода после того, как вы использовали GOTO, чтобы оставить его. Это просто не работает. GOTO немедленно убивает любые разборные кодовые блоки. Вы могли бы также написали код Владислава как:
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
)
Если условие ложно, то весь блок будет пропущен. Если условие TRUE, GOTO немедленно убивает блок, а затем выполнение обычно поднимается на метке: true (без контекста блока). Дополнительный )
в конце просто игнорируется.
Обратите внимание, что вы не можете добавить ELSE с этой конструкцией. Следующие результаты не дают желаемого результата:
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
) else (
echo This will execute regardless whether arg1 is /p or not
)
Если FALSE, то выполняется только блок ELSE. если TRUE, то верхний блок выполняется и сразу же убивается. Остальная часть кода выполняется, а строка ) else (
игнорируется, потому что )
выполняет функции как REM, если синтаксический анализатор ожидает команду, и в стеке нет активных скобок.
Я настоятельно рекомендую вам никогда не использовать GOTO метку в скобках кода в скобках, как я показал выше (или, как сделал Владислав).
Ниже лучше (проще и не вводит в заблуждении) способ сделать то же самое:
@echo off
if not "%1"=="/p" goto :skip
echo "%1"
shift
echo shifted
echo "%1"
:skip
Вы можете поддержать/Then/Else концепции IF с некоторыми дополнительными этикетками и GOTOS
@echo off
if not "%1"=="/p" goto :notP
echo "%1"
shift
echo shifted
echo "%1"
goto :endIf
:notP
echo not /p
:endIf
В итоге я нашел ответ здесь: [Shift не работает в пакетном скрипте] (http://social.technet.microsoft.com/Forums/scriptcenter/en-US/7bbbe8df-e3c0-46ab-aede-396c2b6f6184/shift-doesnt-work-in-batch-script) – piebie