Ответ 1
Это ожидаемое поведение, потому что %1
расширяется, когда строка анализируется, а вся конструкция IF с конечным выражением анализируется за один проход. Таким образом, вы не можете видеть результат SHIFT до тех пор, пока не будет проанализирована новая строка, которая не произойдет до тех пор, пока вы не оставите свой скоброванный блок.
Такая же проблема возникает при расширении переменных среды с использованием %var%
. С переменными окружения вы можете обойти проблему, включив замедленное расширение, используя SETLOCAL EnableDelayedExpansion
а затем используя !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 Код во Владиславе отвечает плохой практикой, так как это означает, что вы можете вернуться в блок кода после того, как вы использовали GOTO, чтобы оставить его. Это просто не работает. GOTO немедленно убивает любые разборные кодовые блоки. Вы могли бы написать код Владислава как:
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
)
Если условие FALSE, то весь блок пропускается. Если условие 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
Вы могли бы поддержать концепцию IF/THEN/ELSE с некоторыми дополнительными ярлыками и GOTO
@echo off
if not "%1"=="/p" goto :notP
echo "%1"
shift
echo shifted
echo "%1"
goto :endIf
:notP
echo not /p
:endIf