Это просто очень плохое сравнение кодированных строк.x
с обеих сторон позволяет сравнивать две строки, даже если %str1:bcd=%
или %str1%
заменены командным процессором Windows при анализе всей командной строки пустой строкой перед выполнением команды IF .
Но выполнение пакетного файла, тем не менее, немедленно прекращается cmd.exe
из-за синтаксической ошибки в случае значения переменной среды str1
содержит символ пробела или "&<>|
.
Заключение строки аргумента в двойные кавычки приводит к получению всех символов, кроме знака процента, и с включенным расширением отложенной переменной среды, а также восклицательного знака, интерпретируемого как буквенный символ, включая пробел, который находится вне строки в двойных кавычках, интерпретируемой как разделитель строки аргумента.* Намного лучше:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" goto EndBatch
set "str1=%~1"
if not "%str1:bcd=%" == "%str1%" echo It contains bcd
:EndBatch
endlocal
Первый аргумент командного файла сравнивается первым без двойных кавычек с пустой строкой.Таким образом, если пакетный файл запускается без какого-либо аргумента или только с ""
в качестве строки первого аргумента, командный процессор Windows выполняет команду GOTO , что приводит к восстановлению предыдущей среды, помещенной в стек, с помощью команды SETLOCAL и выходит из пакетного файла.
В противном случае пакетный файл действительно вызывается со строкой аргумента.Эта строка аргумента присваивается переменной окружения str1
с удалением окружающих двойных кавычек, если они есть.Таким образом, при вызове пакетного файла с аргументом test
значение test
присваивается переменной окружения str1
, а при вызове с помощью "another test"
значение another test
без двойных кавычек присваивается str1
.И даже при вызове пакетного файла с неверно закодированной строкой аргумента "bcd test
(отсутствует секунда "
) только bcd test
присваивается переменной окружения str1
.
IF условие сравнивает значение переменной среды str1
со всеми удаленными вхождениями bcd
со значением неизмененной переменной.Двойные кавычки вокруг двух строк позволяют сравнивать две строки, даже если они содержат пробел или амперсанд или операторы перенаправления <>|
.Команда IF включает в себя двойные кавычки при сравнении двух строк.
Итак, теперь этот код безопасен?
Нет, это не тот случай, когда кто-то вызывает пакетнедопустимый файл с test_bcd"
в качестве строки аргумента, в которой отсутствует первая двойная кавычка.В этом случае первая IF командная строка, выполняемая cmd.exe
:
if "test_bcd"" == "" goto EndBatch
Конечный "
неверно указанной строки аргумента не удаляется cmd.exe
и вызываетсинтаксическая ошибка в этой командной строке при выполнении, которую можно увидеть при запуске командного файла из окна командной строки с изменением первой строки на @echo on
.
Одно из решений без использования отложенного расширения переменной среды:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "str1=%~1"
if not defined str1 goto EndBatch
set "str1=%str1:"=%"
if not defined str1 goto EndBatch
if not "%str1:bcd=%" == "%str1%" echo It contains bcd
:EndBatch
endlocal
Этот код гарантирует, что str1
не содержит никаких двойных кавычек перед выполнением команды IF для сравнения строк.
Другое решение - использование среды с задержкойрасширение переменной:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "str1=%~1"
if not "!str1:bcd=!" == "!str1!" echo It contains bcd
endlocal
Это выглядит лучше, как в приведенном выше коде, без использования отложенного расширения переменной среды.Но он не работает должным образом, если строка аргумента, например, "!Hello!"
, потому что в этом случае условие if not
также верно, и поэтому выводом является сообщение It contains bcd
, хотя строка !Hello!
не содержит bcd
*как буквальные символы.Затем включается отложенное расширение для сравнения строк с использованием отложенного расширения переменной среды, что позволяет избежать изменения самой командной строки с помощью cmd.exe
перед выполнением команды IF .
Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и очень внимательно прочитайте все страницы справки, отображаемые для каждой команды.
call /?
... объясняет %~1
, не так хорошо, как здесь. echo /?
endlocal /?
goto /?
if /?
set /?
setlocal /?
См. Также:
- Как работает интерпретатор команд Windows (CMD.EXE) сценарии синтаксического анализа? ... длинный ответ, который должен тщательно читать каждый автор пакетных файлов сверху вниз.
- forfiles - FALSE против false (не работает с нижнимcase?) ... этот ответ касается обработки аргументов команды IF .
- Символ, эквивалентный NEQ, LSS, GTR и т. д. в пакетных файлах Windows ... этот ответ подробно объясняет, как сравнение строк выполняется командой IF .
- Почему строка не выводится с 'echo% var%' aПосле использования 'set var = text' в командной строке? ... этот ответ объясняет, почему
set "variable=value"
следует использовать в целом, а не в других вариантах. - Одна строка с несколькими командами, использующимиПакетный файл Windows ... объясняет, как
&
и ||
вне строки аргумента в двойных кавычках интерпретируются cmd.exe
. - Статья Microsoft о Использование операторов перенаправления команд объясняет, как
<>|&
вне строки аргумента в двойных кавычках интерпретируется как cmd.exe
.