Ответ 1
Мы провели эксперименты по изучению грамматики пакетных сценариев. Мы также исследовали различия между пакетным режимом и режимом командной строки.
Анализатор Batch Line:
Вот краткий обзор этапов обработки строки кода в командном файле:
Этап 0) Читать строку:
Этап 1) Процент расширения:
Этап 1.5) Удалить <CR>
: Удалить все символы возврата каретки (0x0D)
Этап 2) Обработка специальных символов, токенизация и создание кэшированного блока команд: Это сложный процесс, на который влияют такие вещи, как кавычки, специальные символы, разделители токенов и экранирование кареток.
Этап 3) Отобразить проанализированные команды, только если командный блок не начинался с @
, и ECHO был включен в начале предыдущего шага.
Этап 4) Расширение переменной FOR %X
: Только если команда FOR активна и команды после DO обрабатываются.
Этап 5) Отложенное расширение: Только если включено отложенное расширение
Этап 5.3) Обработка канала: Только если команды находятся на любой стороне канала
Этап 5.5) Выполнить перенаправление:
Этап 6) Обработка CALL/Удвоение каретки: Только если токен команды CALL
Этап 7) Выполнить: Команда выполнена
Вот подробности для каждого этапа:
Обратите внимание, что этапы, описанные ниже, являются лишь моделью того, как работает пакетный анализатор. Фактические внутренние компоненты cmd.exe могут не отражать эти фазы. Но эта модель эффективна для прогнозирования поведения пакетных сценариев.
Фаза 0) Читать строку: Читать строку ввода через первый <LF>
.
- При чтении строки, которая будет проанализирована как команда,
<Ctrl-Z>
(0x1A) читается как<LF>
(LineFeed 0x0A) - Когда GOTO или CALL читают строки во время сканирования на наличие метки:
<Ctrl-Z>
, они обрабатываются как сами по себе - они не преобразуются в<LF>
Этап 1) Процент расширения:
- Двойной
%%
заменяется одним%
- Расширение аргументов (
%*
,%1
,%2
и т.д.) - Расширение
%var%
, если var не существует, заменить его ничем - Сначала строка усекается
<LF>
, но не в расширении%var%
- Для полного объяснения прочитайте первую половину из dbenham Та же тема: Percent Phase
Этап 1.5) Удалить <CR>
: Удалить все возврат каретки (0x0D) из строки
Этап 2) Обработка специальных символов, токенизация и создание кэшированного блока команд: Это сложный процесс, на который влияют такие вещи, как кавычки, специальные символы, разделители токенов и экранирование каретки. Далее следует приблизительное описание этого процесса.
На этом этапе важны концепции.
- Токен - это просто строка символов, которая рассматривается как единое целое.
- Токены разделены разделителями токенов. Стандартными разделителями токенов являются
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
и<0xFF>
Последовательные разделители токенов рассматриваются как единое целое - между разделителями токенов нет пустых токенов - В строке в кавычках нет разделителей токенов. Вся строка в кавычках всегда обрабатывается как часть одного токена. Один токен может состоять из комбинации строк в кавычках и символов без кавычек.
Следующие символы могут иметь особое значение в этой фазе, в зависимости от контекста: ^
(
@
&
|
<
>
<LF>
<space>
<tab>
;
,
] =
<0x0B>
<0x0C>
<0xFF>
Посмотрите на каждого персонажа слева направо:
- Если это каретка (
^
), следующий символ экранируется, а экранирующая каретка удаляется. Экранированные символы теряют все особое значение (кроме<LF>
). - Если это цитата (
"
), переключите флаг цитаты. Если флаг кавычки активен, то только"
и<LF>
являются специальными. Все остальные символы теряют свое особое значение, пока следующая цитата не отключит флаг кавычки. Невозможно избежать закрывающей цитаты. Все цитируемые символы всегда находятся в одном и том же токене. <LF>
всегда выключает флаг кавычки. Другие виды поведения варьируются в зависимости от контекста, но кавычки никогда не меняют поведение<LF>
.- Побег
<LF>
<LF>
раздет- Следующий персонаж сбежал. Если в конце буфера строки, следующая строка считывается и обрабатывается фазами 1 и 1.5 и добавляется к текущей перед экранированием следующего символа. Если следующий символ -
<LF>
, то он рассматривается как литерал, что означает, что этот процесс не является рекурсивным.
- Unescaped
<LF>
не в скобках<LF>
удаляется, и разбор текущей строки прекращается.- Любые оставшиеся символы в буфере строк просто игнорируются.
- Unescaped
<LF>
в блоке FOR IN в скобках<LF>
преобразуется в<space>
- Если в конце буфера строки, следующая строка считывается и добавляется к текущей.
- Unescaped
<LF>
в заключенном в скобки командном блоке<LF>
преобразуется в<LF><space>
, а<space>
обрабатывается как часть следующей строки командного блока.- Если в конце строки находится буфер, то следующая строка читается и добавляется в пробел.
- Побег
- Если это один из специальных символов
&
|
<
или>
, разделите строку в этой точке для обработки каналов, объединения команд и перенаправления.- В случае канала (
|
) каждая сторона представляет собой отдельную команду (или блок команд), которая получает специальную обработку на этапе 5.3 - В случае конкатенации команд
&
,&&
или||
каждая сторона конкатенации рассматривается как отдельная команда. - В случае перенаправления
<
,<<
,>
или>>
предложение перенаправления анализируется, временно удаляется, а затем добавляется в конец текущей команды. Предложение перенаправления состоит из необязательной цифры дескриптора файла, оператора перенаправления и маркера назначения перенаправления.- Если токен, который предшествует оператору перенаправления, представляет собой одну цифру, то эта цифра указывает дескриптор файла для перенаправления. Если маркер дескриптора не найден, по умолчанию перенаправление вывода равно 1 (стандартный вывод), а перенаправление ввода по умолчанию равно 0 (стандартный ввод).
- В случае канала (
- Если самый первый токен для этой команды (до перемещения перенаправления до конца) начинается с
@
, то@
имеет особое значение. (@
не является особенным в любом другом контексте)- Специальный
@
удален. - Если ECHO включен, то эта команда вместе со всеми последующими каскадными командами в этой строке исключаются из эхо-сигнала фазы 3. Если
@
находится перед открытием(
, то весь блок, заключенный в скобки, исключается из эхо-сигнала фазы 3.
- Специальный
- Круглая скобка процесса (содержит составные операторы в несколько строк):
- Если анализатор не ищет маркер команды, то
(
не является специальным. - Если анализатор ищет маркер команды и находит
(
, тогда запустите новый составной оператор и увеличьте счетчик скобок - Если счетчик скобок равен> 0, то
)
завершает составной оператор и уменьшает счетчик скобок. - Если достигнут конец строки и счетчик скобок равен> 0, то следующая строка будет добавлена к составному оператору (начинается снова с фазы 0)
- Если счетчик скобок равен 0 и синтаксический анализатор ищет команду, то
)
функционирует аналогично операторуREM
, если за ним сразу следует разделитель токена, специальный символ, символ новой строки или конец файла- Все специальные символы теряют свое значение, кроме
^
(возможна конкатенация строк) - По достижении конца логической строки вся "команда" отбрасывается.
- Все специальные символы теряют свое значение, кроме
- Если анализатор не ищет маркер команды, то
- Каждая команда разбирается на серию токенов. Первый токен всегда обрабатывается как командный токен (после того как специальный
@
был удален и перенаправление перенесено в конец).- Ведущие разделители токенов перед командным токеном удаляются
- При разборе токена команды,
(
действует как разделитель токена команды, в дополнение к стандартным разделителям токена - Обработка последующих токенов зависит от команды.
- Большинство команд просто объединяют все аргументы после токена команды в один токен аргумента. Все разделители токенов аргументов сохраняются. Параметры аргумента обычно не анализируются до фазы 7.
- Три команды получают специальную обработку - IF, FOR и REM
- Если IF разделен на две или три отдельные части, которые обрабатываются независимо. Синтаксическая ошибка в конструкции IF приведет к фатальной синтаксической ошибке.
- Операция сравнения - это действительная команда, которая проходит всю фазу до фазы 7
- Все опции IF полностью проанализированы на этапе 2.
- Последовательные разделители маркеров сворачиваются в одно пространство.
- В зависимости от оператора сравнения будут определены один или два токена значения.
- Истинный командный блок представляет собой набор команд после условия и анализируется, как и любой другой командный блок. Если необходимо использовать ELSE, тогда блок True должен быть заключен в скобки.
- Необязательный блок False command - это набор команд после ELSE. Опять же, этот командный блок анализируется нормально.
- Командные блоки True и False не переходят автоматически в последующие фазы. Их последующая обработка контролируется на этапе 7.
- Операция сравнения - это действительная команда, которая проходит всю фазу до фазы 7
- FOR делится на две после DO. Синтаксическая ошибка в конструкции FOR приведет к фатальной синтаксической ошибке.
- Часть через DO является фактической итерационной командой FOR, которая проходит всю фазу 7
- Все опции FOR полностью анализируются на этапе 2.
- Предложение в скобках IN обрабатывает
<LF>
как<space>
. После разбора предложения IN все токены объединяются в один токен. - Последовательные разделители токенов без кавычек/без кавычек сворачиваются в единое пространство по всей команде FOR через DO.
- Часть после DO является командным блоком, который анализируется нормально. Последующая обработка командного блока DO контролируется итерацией на этапе 7.
- Часть через DO является фактической итерационной командой FOR, которая проходит всю фазу 7
- REM, обнаруженный в фазе 2, обрабатывается совершенно иначе, чем все другие команды.
- Анализируется только один токен аргумента - анализатор игнорирует символы после первого токена аргумента.
- Команда REM может появиться в выходных данных фазы 3, но команда никогда не выполняется, и исходный текст аргумента отображается - экранирующие символы не удаляются, кроме...
- Если есть только один токен аргумента, который заканчивается неэкранированным
^
, который заканчивает строку, то токен аргумента отбрасывается, а последующая строка анализируется и добавляется в REM. Это повторяется до тех пор, пока не будет более одного токена или последний символ не будет^
.
- Если есть только один токен аргумента, который заканчивается неэкранированным
- Если IF разделен на две или три отдельные части, которые обрабатываются независимо. Синтаксическая ошибка в конструкции IF приведет к фатальной синтаксической ошибке.
- Если жетон команды начинается с
:
, и это первый раунд фазы 2 (не перезапуск из-за ВЫЗОВА в фазе 6), тогда- Маркер обычно рассматривается как неисполненная метка.
- Остальная часть строки анализируется, однако
)
,<
,>
,&
и|
больше не имеют специального значения. Весь остаток строки считается частью метки "команда". ^
продолжает быть особенным, это означает, что продолжение строки можно использовать для добавления следующей строки к метке.- Неисполненная метка в заключенном в скобки блоке приведет к фатальной синтаксической ошибке, если за ней сразу не последует команда или метка выполнения в следующей строке.
(
больше не имеет специального значения для первой команды, которая следует за неисполненной меткой.
- Команда отменяется после завершения анализа метки. Последующие этапы не имеют места для ярлыка
- Остальная часть строки анализируется, однако
- Существует три исключения, которые могут привести к тому, что метка, найденная на этапе 2, будет рассматриваться как исполняемая метка, которая продолжает анализировать на этапе 7.
- Существует перенаправление, которое предшествует токену метки, и на линии имеется конкатенация
|
pipes или команды&
,&&
или||
. - Существует перенаправление, которое предшествует токену метки, а команда находится внутри блока в скобках.
- Маркер метки является самой первой командой в строке внутри блока, заключенного в скобки, а строка выше завершилась неисполненной меткой.
- Существует перенаправление, которое предшествует токену метки, и на линии имеется конкатенация
- Следующее происходит, когда исполняемая метка обнаружена на этапе 2
- Метка, ее аргументы и перенаправление исключены из любого эхо-выхода в фазе 3
- Все последующие составные команды в строке полностью анализируются и выполняются.
- Для получения дополнительной информации о метках "Выполненные" и "Неисполненные" см. https://www.dostips.com/forum/viewtopic.php?f=3&t=3803&p=55405#p55405
- Маркер обычно рассматривается как неисполненная метка.
Этап 3) Отобразите проанализированные команды, только если командный блок не начинался с @
, и ECHO был включен в начале предыдущего шага.
Этап 4) Расширение переменной FOR %X
: Только если команда FOR активна и команды после DO обрабатываются.
- На этом этапе фаза 1 пакетной обработки уже преобразует переменную FOR, например,
%%X
, в%X
. Командная строка имеет разные правила процентного расширения для фазы 1. По этой причине командные строки используют%X
, но командные файлы используют%%X
для переменных FOR. - Имена переменных FOR чувствительны к регистру, но
~modifiers
не чувствительны к регистру. ~modifiers
имеет приоритет над именами переменных. Если символ, следующий за~
, является одновременно модификатором и допустимым именем переменной FOR, и существует последующий символ, который является активным именем переменной FOR, тогда этот символ интерпретируется как модификатор.- Имена переменных FOR являются глобальными, но только в контексте предложения DO. Если подпрограмма вызывается из предложения FOR DO, то переменные FOR не раскрываются в подпрограмме CALLed. Но если у подпрограммы есть собственная команда FOR, то все переменные, определенные в настоящее время, FOR доступны для внутренних команд DO.
- Имена переменных FOR могут быть повторно использованы во вложенных FOR. Внутреннее значение FOR имеет приоритет, но после закрытия INNER FOR внешнее значение FOR восстанавливается.
- Если ECHO был включен в начале этого этапа, то этап 3) повторяется, чтобы показать проанализированные команды DO после расширения переменных FOR.
---- С этого момента каждая команда, определенная на этапе 2, обрабатывается отдельно.
---- Фазы с 5 по 7 завершены для одной команды, прежде чем перейти к следующей.
Этап 5) Отложенное расширение: Только если отложенное расширение включено, команда не находится в блоке с круглыми скобками по обе стороны канала, и команда не является "голым" пакетом сценарий (имя сценария без скобок, CALL, объединение команд или канал).
- Каждый токен для команды анализируется для отложенного расширения независимо.
- Большинство команд анализируют два или более токенов - токен команды, токен аргументов и каждый токен назначения перенаправления.
- Команда FOR анализирует только токен предложения IN.
- Команда IF анализирует только значения сравнения - одно или два, в зависимости от оператора сравнения.
- Для каждого проанализированного токена сначала проверьте, есть ли в нем
!
. Если нет, то токен не анализируется - важно для символов^
. Если токен содержит!
, отсканируйте каждый символ слева направо:- Если это каретка (
^
), следующий символ не имеет особого значения, сама каретка удаляется - Если это восклицательный знак, ищите следующий восклицательный знак (каретки больше не наблюдаются), разверните значение переменной.
- Последовательное открытие
!
свернуто в один!
- Все оставшиеся непарные
!
удаляются
- Последовательное открытие
- Расширение vars на этом этапе "безопасно", потому что специальные символы больше не обнаруживаются (даже
<CR>
или<LF>
) - Для более полного объяснения, прочитайте 2-ую половину этого от dbenham та же тема - Фаза восклицательного знака
- Если это каретка (
Этап 5.3) Обработка канала: Только если команды находятся на любой стороне канала
Каждая сторона канала обрабатывается независимо и асинхронно.
- Если команда является внутренней для cmd.exe, или это командный файл, или если это командный блок в скобках, то он выполняется в новом потоке cmd.exe через
%comspec% /S /D /c" commandBlock"
, поэтому командный блок получает фазовый перезапуск, но на этот раз в режиме командной строки.- Если блок команд заключен в скобки, то все
<LF>
с командой до и после преобразуются в<space>&
. Другие<LF>
лишены.
- Если блок команд заключен в скобки, то все
- Это конец обработки для конвейерных команд.
- См. Почему отложенное расширение завершается неудачно, когда он находится внутри конвейерного блока кода?, чтобы узнать больше о разборе и обработке канала
Этап 5.5) Выполнить перенаправление: Любое перенаправление, обнаруженное на этапе 2, теперь выполняется.
- Результаты этапов 4 и 5 могут повлиять на перенаправление, обнаруженное на этапе 2.
- Если перенаправление завершится неудачно, то остальная часть команды будет прервана. Обратите внимание, что при сбое перенаправления значение ERRORLEVEL не устанавливается на 1, если только
||
не используется.
Этап 6) Обработка CALL/Удвоение каретки: Только если токен команды - CALL или если текст перед первым встречающимся стандартным разделителем токена - CALL. Если CALL анализируется из большего токена команды, то перед продолжением перед неиспользуемой частью ставится токен аргументов.
- Сканируйте маркер аргументов на предмет отсутствия кавычек
/?
. Если найден где-нибудь в пределах токенов, прервите фазу 6 и перейдите к Фазе 7, где будет напечатана ПОМОЩЬ для ВЫЗОВА. - Удалите первый
CALL
, чтобы несколько CALL могли быть сложены - Удвойте все каретки
- Перезапустите фазы 1, 1.5 и 2, но не переходите к фазе 3
- Любые двойные каретки сокращаются до одной каретки, если они не указаны. Но, к сожалению, котировки остаются в два раза.
- Фаза 1 немного меняется
- Ошибки расширения на шаге 1.2 или 1.3 отменяют CALL, но ошибка не является фатальной - пакетная обработка продолжается.
- Задачи Фазы 2 немного изменены
- Любое вновь появляющееся перенаправленное без кавычек, неэкранированное, которое не было обнаружено в первом раунде фазы 2, обнаружено, но оно удалено (включая имя файла) без фактического выполнения перенаправления
- Любая вновь появляющаяся нецитированная, неэкранированная каретка в конце строки удаляется без продолжения строки
- CALL отменяется без ошибок, если обнаруживается любое из следующего
- Вновь появившиеся без кавычек, неэкранированные
&
или|
- Полученный в результате токен команды начинается без кавычек, без экранирования
(
- Самый первый токен после удаленного CALL начался с
@
- Вновь появившиеся без кавычек, неэкранированные
- Если результирующая команда является, по-видимому, допустимой IF или FOR, то впоследствии выполнение завершится неудачно с ошибкой, сообщающей, что
IF
илиFOR
не распознаются как внутренняя или внешняя команда. - Разумеется, CALL не прерывается во втором раунде фазы 2, если результирующий токен команды является меткой, начинающейся с
:
.
- Если результирующим токеном команды является CALL, перезапустите этап 6 (повторяется до тех пор, пока CALL больше не будет)
- Если результирующий токен команды представляет собой пакетный сценарий или метку:, то выполнение CALL полностью обрабатывается оставшейся частью этапа 6.
- Выдвиньте текущую позицию файла пакетного сценария в стеке вызовов, чтобы выполнение могло возобновиться с правильной позиции после завершения вызова.
- Установите маркеры аргументов% 0,% 1,% 2,...% N и% * для CALL, используя все полученные токены
- Если маркер команды является меткой, начинающейся с
:
, то- Перезапустите этап 5. Это может повлиять на то, что: CALLED. Но поскольку токены% 0 и т.д. Уже настроены, они не изменят аргументы, передаваемые подпрограмме CALLed.
- Выполните метку GOTO, чтобы поместить указатель файла в начало подпрограммы (не обращайте внимания на любые другие токены, которые могут следовать за меткой:). См. на этапе 7 правила о том, как работает GOTO.
- Если токен: label отсутствует или метка: не найдена, то стек вызовов немедленно извлекается для восстановления позиции сохраненного файла, и CALL прерывается.
- Если метка: содержит /?, То вместо поиска метки выводится справка GOTO. Указатель файла не перемещается, так что код после CALL выполняется дважды, один раз в контексте CALL, а затем снова после возврата CALL. См. Почему CALL печатает справочное сообщение GOTO в этом сценарии? И почему после этого команда выполняется дважды? для получения дополнительной информации.
- В противном случае передать управление указанному пакетному сценарию.
- Выполнение метки или сценария CALLed: продолжается до тех пор, пока не будет достигнут EXIT/B или конец файла, после чего стек CALL будет извлечен, и выполнение возобновится с позиции сохраненного файла.
Этап 7 не выполняется для сценариев CALLed или: меток.
- В противном случае результат этапа 6 переходит в этап 7 для выполнения.
Этап 7) Выполнить: Команда выполнена
- 7.1 - Выполнить внутреннюю команду - Если токен команды указан в кавычках, пропустите этот шаг. В противном случае попытайтесь разобрать внутреннюю команду и выполнить.
- Следующие тесты сделаны, чтобы определить, представляет ли токен команды без кавычек внутреннюю команду:
- Если маркер команды точно соответствует внутренней команде, выполните ее.
- Иначе сломайте токен команды до первого появления
+
/
[
]
<space>
<tab>
,
;
или=
Если предыдущий текст является внутренней командой, то запомните эту команду- Если в режиме командной строки или команда из блока в скобках, командного блока ЕСЛИ истина или ложь, командного блока FOR DO или связана с объединением команд, выполните внутреннюю команду
- В противном случае (должна быть автономной командой в пакетном режиме) сканировать текущую папку и PATH на наличие файла .COM,.EXE,.BAT или .CMD, базовое имя которого соответствует исходному токену команды.
- Если первый соответствующий файл -.BAT или .CMD, перейдите к 7.3.exec и выполните этот скрипт
- .В противном случае (совпадение не найдено или первое совпадение -.EXE или .COM) выполните запомненную внутреннюю команду
- Иначе сломайте токен команды до первого появления
.
\
или:
Если предыдущий текст не является внутренней командой, перейдите к 7.2
В противном случае предыдущий текст может быть внутренней командой. Запомните эту команду. - Разбейте маркер команды до первого появления
+
/
[
]
<space>
<tab>
,
;
или=
Если предыдущий текст является путем к существующему файлу, перейдите к 7.2
В противном случае выполните запомненную внутреннюю команду.
- Если внутренняя команда анализируется из большого токена команды, то неиспользованная часть токена команды включается в список аргументов
- То, что маркер команды анализируется как внутренняя команда, не означает, что она будет выполнена успешно. Каждая внутренняя команда имеет свои собственные правила анализа параметров и параметров и допустимого синтаксиса.
- Все внутренние команды выводят справку вместо выполнения своих функций, если обнаружен
/?
. Большинство распознают/?
, если оно появляется где-либо в аргументах. Но некоторые команды, такие как ECHO и SET, выводят справку только в том случае, если маркер первого аргумента начинается с/?
. - У SET есть интересная семантика:
- Если команда SET содержит кавычку до того, как имя переменной и расширения будут включены
set "name=content" ignored
-> value =content
затем в качестве содержимого используется текст между первым знаком равенства и последней цитатой (исключая первое равенство и последнюю цитату). Текст после последней цитаты игнорируется. Если после знака равенства нет кавычек, то остальная часть строки используется в качестве содержимого. - Если команда SET не имеет кавычки перед именем
set name="content" not ignored
-> value ="content" not ignored
затем весь остаток строки после равенства используется в качестве содержимого, включая любые и все кавычки, которые могут присутствовать.
- Если команда SET содержит кавычку до того, как имя переменной и расширения будут включены
- Сравнение IF вычисляется, и в зависимости от того, является ли условие истинным или ложным, обрабатывается соответствующий уже проанализированный зависимый блок команд, начиная с фазы 5.
- Предложение IN команды FOR повторяется соответствующим образом.
- Если это FOR/F, который повторяет вывод командного блока, то:
- Предложение IN выполняется в новом процессе cmd.exe через CMD/C.
- Блок команд должен пройти весь процесс синтаксического анализа во второй раз, но на этот раз в контексте командной строки
- ECHO запустится ВКЛ, а отложенное расширение обычно будет отключено (зависит от настроек реестра)
- Все изменения среды, сделанные командным блоком предложения IN, будут потеряны после завершения дочернего процесса cmd.exe
- Для каждой итерации:
- Определены значения переменных FOR
- Уже обработанный блок команд DO обрабатывается, начиная с фазы 4.
- Если это FOR/F, который повторяет вывод командного блока, то:
- GOTO использует следующую логику для поиска метки:
- Метка анализируется с токена первого аргумента
- Сценарий сканируется для следующего появления метки
- Сканирование начинается с текущей позиции файла
- Если достигнут конец файла, то сканирование возвращается к началу файла и продолжается до исходной начальной точки.
- Сканирование останавливается при первом появлении найденной метки, а указатель файла устанавливается на строку, следующую непосредственно за меткой. Выполнение сценария возобновляется с этого момента. Обратите внимание, что успешное истинное GOTO немедленно прервет любой проанализированный блок кода, включая циклы FOR.
- Если метка не найдена или токен метки отсутствует, то GOTO завершается ошибкой, печатается сообщение об ошибке и извлекается стек вызовов. Это эффективно работает как EXIT/B, за исключением того, что все уже проанализированные команды в текущем командном блоке, которые следуют за GOTO, все еще выполняются, но в контексте CALLer (контекст, который существует после EXIT/B)
- См. https://www.dostips.com/forum/viewtopic.php?f=3&t=3803 для более точного описания правил, используемых для анализа меток.
- RENAME и COPY принимают подстановочные знаки для исходного и целевого путей. Но Microsoft делает ужасную работу, документируя, как работают шаблоны, особенно для целевого пути. Полезный набор правил подстановочных знаков можно найти на . Как команда Windows RENAME интерпретирует подстановочные знаки?
- Следующие тесты сделаны, чтобы определить, представляет ли токен команды без кавычек внутреннюю команду:
- 7.2 - Выполнить изменение громкости - В противном случае, если токен команды не начинается с кавычки, имеет длину ровно два символа, а второй символ - двоеточие, измените громкость
- Все токены аргументов игнорируются
- Если громкость, указанную первым символом, не может быть найдена, прервать с ошибкой
- Токен команды
::
всегда будет приводить к ошибке, если SUBST не используется для определения тома для::
Если SUBST используется для определения громкости для::
, то громкость будет изменена, она не будет рассматриваться как метка.
- 7.3 - Выполнить внешнюю команду - Иначе попытаться обработать команду как внешнюю команду.
- Если в режиме командной строки команда не заключена в кавычки и не начинается со спецификации тома, разбейте токен команды при первом появлении
<space>
,
;
или=
и добавьте остаток к аргументу маркер (ы). - Если вторым символом токена команды является двоеточие, проверьте, найден ли объем, заданный первым символом.
Если том не найден, прервитесь с ошибкой. - Если в пакетном режиме токен команды начинается с
:
, то перейдите к 7.4
Обратите внимание, что если маркер метки начинается с::
, то он не будет достигнут, поскольку предыдущий шаг будет прерван с ошибкой, если SUBST не используется для определения тома для::
. - Определите внешнюю команду для выполнения.
- Это сложный процесс, который может включать текущий том, текущий каталог, переменную PATH, переменную PATHEXT и/или ассоциации файлов.
- Если действительная внешняя команда не может быть идентифицирована, прервитесь с ошибкой.
- Если в режиме командной строки токен команды начинается с
:
, то перейдите к 7.4
Обратите внимание, что это редко достигается, потому что предыдущий шаг будет прерван с ошибкой, если токен команды не начинается с::
, а SUBST используется для определения тома для::
, а весь токен команды является допустимым путем к внешняя команда. - 7.3.exec - выполнить внешнюю команду.
- Если в режиме командной строки команда не заключена в кавычки и не начинается со спецификации тома, разбейте токен команды при первом появлении
- 7.4 - Игнорировать метку - Игнорировать команду и все ее аргументы, если маркер команды начинается с
:
.
Правила в 7.2 и 7.3 могут помешать этикетке достичь этой точки.
Анализатор командной строки:
Работает как BatchLine-Parser, кроме:
Этап 1) Процент расширения:
- Нет
%*
,%1
и т.д. Расширение аргумента - Если var не определено, то
%var%
остается без изменений. - Никакой специальной обработки
%%
. Если var = content, то%%var%%
расширяется до%content%
.
Этап 3) Отобразить проанализированные команды
- Это не выполняется после фазы 2. Это выполняется только после фазы 4 для блока команд FOR DO.
Этап 5) Отсроченное расширение: только если включено DelayedExpansion
- Если var не определено, то
!var!
остается без изменений.
Этап 7) Выполнить команду
- Попытки CALL или GOTO a: label приводят к ошибке.
- Как уже задокументировано на этапе 7, выполненная метка может привести к ошибке при различных сценариях.
- Пакетно выполненные метки могут вызвать ошибку, только если они начинаются с
::
- Выполненные в командной строке метки почти всегда приводят к ошибке
- Пакетно выполненные метки могут вызвать ошибку, только если они начинаются с
Разбор целочисленных значений
Существует множество различных контекстов, в которых cmd.exe анализирует целочисленные значения из строк, а правила противоречивы:
SET /A
IF
%var:~n,m%
(расширение подстроки переменной)FOR /F "TOKENS=n"
FOR /F "SKIP=n"
FOR /L %%A in (n1 n2 n3)
EXIT [/B] n
Подробности этих правил можно найти в Правилах того, как CMD.EXE анализирует числа
.Для тех, кто хочет улучшить правила синтаксического анализа cmd.exe, на форуме DosTips есть тема обсуждения, где можно сообщать о проблемах и вносить предложения.
Надеюсь, это поможет
Ян Эрик (Джеб) - оригинальный автор и первооткрыватель фаз
Dave Benham (dbenham) - много дополнительного контента и редактирования