Realizamos experimentos para investigar a gramática dos scripts em lote. Também investigamos as diferenças entre os modos de lote e de linha de comando.
Analisador de Linha de Lote:
Aqui está uma breve visão geral das fases no analisador de linha de arquivo em lote:
Fase 0) Linha de Leitura:
Fase 1) Porcentagem de expansão:
Fase 2) Processar caracteres especiais, tokenizar e criar um bloco de comando em cache: Esse é um processo complexo que é afetado por coisas como aspas, caracteres especiais, delimitadores de token e escapes de sinal de intercalação.
Fase 3) Repetir o (s) comando (s) analisado (s) Somente se o bloco de comando não tiver começado @
e o ECHO estava LIGADO no início da etapa anterior.
Fase 4) %X
Expansão da variável FOR : Somente se um comando FOR estiver ativo e os comandos após o DO estiverem sendo processados.
Fase 5) Expansão atrasada: somente se a expansão atrasada estiver ativada
Fase 5.3) Processamento do tubo: somente se os comandos estiverem em ambos os lados de um tubo
Fase 5.5) Executar redirecionamento:
Fase 6) Processamento de CHAMADA / duplicação de intercalação: somente se o token de comando for CHAMADA
Fase 7) Execute: O comando é executado
Aqui estão os detalhes para cada fase:
Observe que as fases descritas abaixo são apenas um modelo de como o analisador de lotes funciona. Os internos reais do cmd.exe podem não refletir essas fases. Mas esse modelo é eficaz em prever o comportamento de scripts em lote.
Fase 0) Read Line: Leia a linha de entrada primeiro <LF>
.
- Ao ler uma linha a ser analisada como um comando,
<Ctrl-Z>
(0x1A) é lido como <LF>
(LineFeed 0x0A)
- Quando GOTO ou ligue lê linhas durante a digitalização para um: etiqueta,
<Ctrl-Z>
, é tratado como si - é não convertida em<LF>
Fase 1) Porcentagem de expansão:
- Um duplo
%%
é substituído por um único%
- Expansão de argumentos (
%*
, %1
, %2
, etc.)
- Expansão de
%var%
, se var não existir, substitua-o por nada
- A linha é truncada no início,
<LF>
não dentro da %var%
expansão
- Para obter uma explicação completa, leia a primeira metade disso em dbenham .
Fase 2) Processar caracteres especiais, tokenizar e criar um bloco de comando em cache: Esse é um processo complexo que é afetado por coisas como aspas, caracteres especiais, delimitadores de token e escapes de sinal de intercalação. O que se segue é uma aproximação deste processo.
Existem conceitos que são importantes ao longo desta fase.
- Um token é simplesmente uma sequência de caracteres que é tratada como uma unidade.
- Os tokens são separados por delimitadores de token. Os delimitadores de token padrão são
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
e delimitadores <0xFF>
consecutivos de token são tratados como um - não há tokens vazios entre os delimitadores de token
- Não há delimitadores de token em uma sequência de caracteres citada. Toda a cadeia de caracteres citada é sempre tratada como parte de um único token. Um único token pode consistir em uma combinação de seqüências de caracteres entre aspas e caracteres não entre aspas.
Os seguintes caracteres podem ter um significado especial nesta fase, dependendo do contexto: <CR>
^
(
@
&
|
<
>
<LF>
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
<0xFF>
Observe cada caractere da esquerda para a direita:
- Se, em
<CR>
seguida, remova-o, como se nunca estivesse lá (exceto pelo comportamento de redirecionamento estranho )
- Se um sinal de intercalação (
^
), o próximo caractere é escapado e o cursor de intercalação é removido. Caracteres escapados perdem todo significado especial (exceto <LF>
).
- Se uma citação (
"
), alterne o sinalizador de citação. Se o sinalizador de cotação estiver ativo, apenas "
e <LF>
será especial. Todos os outros caracteres perdem seu significado especial até que a próxima citação desative o sinalizador de citação. Não é possível escapar da cotação de fechamento. Todos os caracteres citados estão sempre no mesmo token.
<LF>
sempre desativa o sinalizador de cotação. Outros comportamentos variam dependendo do contexto, mas as aspas nunca alteram o comportamento de <LF>
.
- Escapou
<LF>
<LF>
é despojado
- O próximo caractere é escapado. Se no final do buffer da linha, a próxima linha é lida e processada pelas fases 1 e 1.5 e anexada à atual antes de escapar do próximo caractere. Se o próximo caractere for
<LF>
, ele será tratado como um literal, o que significa que esse processo não é recursivo.
- Sem escape
<LF>
entre parênteses
<LF>
é retirado e a análise da linha atual é encerrada.
- Quaisquer caracteres restantes no buffer de linha são simplesmente ignorados.
- Sem escape
<LF>
dentro de um bloco entre parênteses FOR IN
<LF>
é convertido em um <space>
- Se no final do buffer da linha, a próxima linha será lida e anexada à atual.
- Sem escape
<LF>
dentro de um bloco de comando entre parênteses
<LF>
é convertido em <LF><space>
e <space>
é tratado como parte da próxima linha do bloco de comando.
- Se no final do buffer da linha, a próxima linha será lida e anexada ao espaço.
- Se um dos caracteres especiais
&
|
<
ou >
, dividir a linha neste ponto, a fim de manipular pipes, concatenação de comandos e redirecionamento.
- No caso de um pipe (
|
), cada lado é um comando (ou bloco de comando) separado que recebe tratamento especial na fase 5.3
- No caso de
&
, &&
ou ||
concatenação de comando, cada lado da concatenação é tratado como um comando separado.
- No caso de
<
, <<
, >
, ou >>
redirecionamento, a cláusula de redireccionamento é analisado, temporariamente removido e, em seguida acrescentado ao final da corrente de comando. Uma cláusula de redirecionamento consiste em um dígito de identificador de arquivo opcional, o operador de redirecionamento e o token de destino do redirecionamento.
- Se o token que precede o operador de redirecionamento for um único dígito sem escape, o dígito especificará o identificador do arquivo a ser redirecionado. Se o token de identificador não for encontrado, o padrão de redirecionamento de saída será 1 (stdout) e o padrão de redirecionamento de entrada será 0 (stdin).
- Se o primeiro token para esse comando (antes de mover o redirecionamento para o final) começar com
@
, ele @
terá um significado especial. ( @
não é especial em nenhum outro contexto)
- O especial
@
é removido.
- Se ECHO estiver LIGADO, esse comando, juntamente com os seguintes comandos concatenados nesta linha, serão excluídos do eco da fase 3. Se
@
antes de uma abertura (
, todo o bloco entre parênteses é excluído do eco da fase 3.
- Parênteses de processo (fornece instruções compostas em várias linhas):
- Se o analisador não estiver procurando por um token de comando, ele
(
não será especial.
- Se o analisador estiver procurando por um token de comando e localizar
(
, inicie uma nova instrução composta e aumente o contador de parênteses
- Se o contador de parênteses for> 0,
)
encerre a instrução composta e diminua o contador de parênteses.
- Se o final da linha for alcançado e o contador de parênteses for> 0, a próxima linha será anexada à instrução composta (inicia novamente com a fase 0)
- Se o contador de parênteses for 0 e o analisador estiver procurando por um comando,
)
funcionará de maneira semelhante a uma REM
instrução, desde que seja imediatamente seguido por um delimitador de token, caractere especial, nova linha ou fim de arquivo
- Todos os caracteres especiais perdem o significado, exceto
^
(é possível concatenação de linha)
- Quando o final da linha lógica é alcançado, todo o "comando" é descartado.
- Cada comando é analisado em uma série de tokens. O primeiro token é sempre tratado como um token de comando (depois que o especial
@
é retirado e o redirecionamento movido para o final).
- Os delimitadores de token iniciais antes do token de comando são removidos
- Ao analisar o token de comando, ele
(
funciona como um delimitador de token de comando, além dos delimitadores de token padrão
- A manipulação de tokens subsequentes depende do comando.
- A maioria dos comandos simplesmente concatena todos os argumentos após o token de comando em um único token de argumento. Todos os delimitadores de token de argumento são preservados. As opções de argumento geralmente não são analisadas até a fase 7.
- Três comandos recebem tratamento especial - IF, FOR e REM
- O IF é dividido em duas ou três partes distintas que são processadas independentemente. Um erro de sintaxe na construção SE resultará em um erro fatal de sintaxe.
- A operação de comparação é o comando real que flui até a fase 7
- Todas as opções de FI são totalmente analisadas na fase 2.
- Delimitadores consecutivos de tokens são recolhidos em um único espaço.
- Dependendo do operador de comparação, haverá um ou dois tokens de valor que são identificados.
- O bloco de comandos True é o conjunto de comandos após a condição e é analisado como qualquer outro bloco de comandos. Se ELSE deve ser usado, o bloco True deve estar entre parênteses.
- O bloco de comandos False opcional é o conjunto de comandos após ELSE. Novamente, esse bloco de comando é analisado normalmente.
- Os blocos de comando Verdadeiro e Falso não fluem automaticamente para as fases subseqüentes. O processamento subsequente é controlado pela fase 7.
- FOR é dividido em dois após o DO. Um erro de sintaxe na construção FOR resultará em um erro de sintaxe fatal.
- A parte através do DO é o comando de iteração FOR real que flui por toda a fase 7
- Todas as opções FOR são totalmente analisadas na fase 2.
- A cláusula entre parênteses IN trata
<LF>
como <space>
. Após a análise da cláusula IN, todos os tokens são concatenados juntos para formar um único token.
- Delimitadores de token consecutivos sem escape / sem aspas são recolhidos em um único espaço em todo o comando FOR através do DO.
- A parte após DO é um bloco de comando que é analisado normalmente. O processamento subsequente do bloco de comando DO é controlado pela iteração na fase 7.
- O REM detectado na fase 2 é tratado dramaticamente diferente de todos os outros comandos.
- Apenas um token de argumento é analisado - o analisador ignora caracteres após o primeiro token de argumento.
- O comando REM pode aparecer na saída da fase 3, mas o comando nunca é executado e o texto do argumento original é repetido - os pontos de intercalação que escapam não são removidos, exceto ...
- Se houver apenas um token de argumento que termina com um sem escape
^
que termina a linha, o token de argumento é jogado fora e a linha subseqüente é analisada e anexada ao REM. Isso se repete até que haja mais de um token ou o último caractere não ^
.
- Se o token de comando começar com
:
e esta for a primeira rodada da fase 2 (não uma reinicialização devido a CALL na fase 6),
- O token é normalmente tratado como um rótulo não executado .
- O restante da linha é analisado, no entanto
)
, <
, >
, &
e |
já não têm significado especial. O restante da linha é considerado parte do rótulo "comando".
- O
^
continua a ser especial, o que significa que a continuação da linha pode ser usada para acrescentar a linha subseqüente ao rótulo.
- Um Rótulo Não Executado dentro de um bloco entre parênteses resultará em um erro fatal de sintaxe, a menos que seja imediatamente seguido por um comando ou Rótulo Executado na próxima linha.
(
não tem mais um significado especial para o primeiro comando que segue o Rótulo Não Executado .
- O comando é interrompido após a conclusão da análise de rótulo. As fases subsequentes não ocorrem para o rótulo
- Há três exceções que podem fazer com que um rótulo encontrado na fase 2 seja tratado como um rótulo executado que continua analisando a fase 7.
- Há redirecionamento que precede o rótulo de símbolo, e há um
|
tubo ou &
, &&
ou ||
concatenação de comando na linha.
- Há um redirecionamento que precede o token do rótulo e o comando está dentro de um bloco entre parênteses.
- O token do rótulo é o primeiro comando em uma linha dentro de um bloco entre parênteses, e a linha acima terminou com um Rótulo Não Executado .
- O seguinte ocorre quando um rótulo executado é descoberto na fase 2
- O rótulo, seus argumentos e seu redirecionamento são todos excluídos de qualquer saída de eco na fase 3
- Quaisquer comandos concatenados subsequentes na linha são totalmente analisados e executados.
- Para mais informações sobre etiquetas Executados vs. Labels não executadas , consulte https://www.dostips.com/forum/viewtopic.php?f=3&t=3803&p=55405#p55405
Fase 3) Repetir o (s) comando (s) analisado (s) Somente se o bloco de comando não tiver começado @
e o ECHO estava LIGADO no início da etapa anterior.
Fase 4) %X
Expansão da variável FOR : Somente se um comando FOR estiver ativo e os comandos após o DO estiverem sendo processados.
- Neste ponto, a fase 1 do processamento em lote já terá convertido uma variável FOR como
%%X
em %X
. A linha de comando possui regras de expansão percentual diferentes para a fase 1. Esse é o motivo pelo qual as linhas de comando usam, %X
mas os arquivos em lote usam %%X
para variáveis FOR.
- Os nomes de variáveis FOR diferenciam maiúsculas de minúsculas, mas
~modifiers
não diferenciam maiúsculas de minúsculas.
~modifiers
tem precedência sobre nomes de variáveis. Se um caractere a seguir ~
for um modificador e um nome de variável FOR válido, e existir um caractere subsequente que seja um nome de variável FOR ativo, o caractere será interpretado como um modificador.
- Os nomes de variáveis FOR são globais, mas apenas dentro do contexto de uma cláusula DO. Se uma rotina for CHAMADA de dentro de uma cláusula FOR DO, as variáveis FOR não serão expandidas dentro da rotina CALLed. Mas se a rotina tiver seu próprio comando FOR, todas as variáveis FOR atualmente definidas estarão acessíveis aos comandos DO internos.
- Os nomes de variáveis FOR podem ser reutilizados em FORs aninhados. O valor interno de FOR tem precedência, mas quando o INNER FOR é fechado, o valor externo de FOR é restaurado.
- Se o ECHO estava LIGADO no início desta fase, a fase 3) é repetida para mostrar os comandos DO analisados após a expansão das variáveis FOR.
---- A partir deste momento, cada comando identificado na fase 2 é processado separadamente.
---- As fases 5 a 7 são concluídas para um comando antes de passar para o próximo.
Fase 5) Expansão atrasada: somente se a expansão atrasada estiver ativada, o comando não estará em um bloco entre parênteses nos dois lados de um canal e o comando não será um script em lote "nu" (nome do script sem parênteses, CALL, concatenação de comando, ou tubo).
- Cada token para um comando é analisado para expansão atrasada independentemente.
- A maioria dos comandos analisa dois ou mais tokens - o token de comando, o token de argumentos e cada token de destino de redirecionamento.
- O comando FOR analisa apenas o token da cláusula IN.
- O comando SE analisa apenas os valores de comparação - um ou dois, dependendo do operador de comparação.
- Para cada token analisado, verifique primeiro se ele contém algum
!
. Caso contrário, o token não será analisado - importante para os ^
caracteres. Se o token contiver !
, verifique cada caractere da esquerda para a direita:
- Se for um sinal de intercalação (
^
), o próximo caractere não tem significado especial, o próprio intercalação é removido
- Se for um ponto de exclamação, procure o próximo ponto de exclamação (os sinais de intercalação não são mais observados), expanda para o valor da variável.
- A abertura consecutiva
!
é recolhida em um único!
- Qualquer restante não pareado
!
é removido
- A expansão de vars nesse estágio é "segura", porque caracteres especiais não são mais detectados (pares
<CR>
ou <LF>
)
- Para uma explicação mais completa, leia a segunda metade disso no dbenham
same thread - Fase do ponto de exclamação
Fase 5.3) Processamento do tubo: Somente se os comandos estiverem em ambos os lados de um tubo.
Cada lado do tubo é processado de forma independente e assíncrona.
- Se o comando for interno ao cmd.exe, ou se for um arquivo em lotes ou se for um bloco de comando entre parênteses, ele será executado em um novo encadeamento do cmd.exe
%comspec% /S /D /c" commandBlock"
, para que o bloco de comando obtenha uma reinicialização de fase, mas desta vez no modo de linha de comando.
- Se um bloco de comando entre parênteses, todos
<LF>
com um comando antes e depois serão convertidos em <space>&
. Outros <LF>
são despidos.
- Este é o fim do processamento para os comandos de canal.
- Consulte Por que a expansão atrasada falha quando dentro de um bloco de código canalizado? para saber mais sobre análise e processamento de tubos
Fase 5.5) Executar redirecionamento: Qualquer redirecionamento descoberto na fase 2 agora é executado.
Fase 6) Processamento de CHAMADA / duplicação de intercalação: Somente se o token de comando for CALL ou se o texto antes do primeiro delimitador de token padrão ocorrer for CALL. Se CALL for analisado a partir de um token de comando maior, a parte não utilizada será anexada ao token de argumentos antes de continuar.
- Analise o token de argumentos em busca de aspas
/?
. Se encontrado em qualquer lugar dentro dos tokens, aborte a fase 6 e prossiga para a fase 7, onde a HELP for CALL será impressa.
- Remova a primeira
CALL
, para que várias CALLs possam ser empilhadas
- Dobrar todos os pontos de intercalação
- Reinicie as fases 1, 1,5 e 2, mas não continue para a fase 3
- Qualquer sinal de intercalação dobrado é reduzido novamente para um sinal de intercalação, desde que não esteja entre aspas. Infelizmente, porém, os circuitos cotados permanecem dobrados.
- A fase 1 muda um pouco
- Os erros de expansão na etapa 1.2 ou 1.3 abortam a CHAMADA, mas o erro não é fatal - o processamento em lote continua.
- As tarefas da fase 2 são um pouco alteradas
- Qualquer novo redirecionamento sem aspas e sem aspas que não foi detectado na primeira rodada da fase 2 é detectado, mas é removido (incluindo o nome do arquivo) sem realmente executar o redirecionamento
- Qualquer novo sinal de intercalação sem aspas e sem aspas no final da linha é removido sem executar a continuação da linha
- A CHAMADA é interrompida sem erro se alguma das seguintes situações for detectada
- Aparecendo recentemente sem aspas, sem escape
&
ou|
- O token de comando resultante começa com sem aspas, sem escape
(
- O primeiro token após a chamada removida começou com
@
- Se o comando resultante for um IF ou FOR aparentemente válido, a execução falhará subsequentemente com um erro informando que
IF
ou FOR
não é reconhecido como um comando interno ou externo.
- É claro que o CALL não será abortado nesta 2ª rodada da fase 2 se o token de comando resultante for um rótulo começando com
:
.
- Se o token de comando resultante for CALL, reinicie a Fase 6 (repete até que não haja mais CALL)
- Se o token de comando resultante for um script em lote ou um rótulo:, a execução do CALL será totalmente tratada pelo restante da Fase 6.
- Empurre a posição atual do arquivo de script em lote na pilha de chamadas para que a execução possa retomar da posição correta quando a CHAMADA for concluída.
- Configure os tokens de argumento% 0,% 1,% 2, ...% N e% * para o CALL, usando todos os tokens resultantes
- Se o token de comando for um rótulo que comece com
:
,
- Reinicie a Fase 5. Isso pode afetar o que: o rótulo é CHAMADO. Mas como os tokens% 0 etc. já foram configurados, ele não alterará os argumentos passados para a rotina CALLed.
- Execute o rótulo GOTO para posicionar o ponteiro do arquivo no início da sub-rotina (ignore outros tokens que possam seguir o: rótulo). Consulte a Fase 7 para obter regras sobre como o GOTO funciona.
- Se o token: label estiver ausente ou o label: não for encontrado, a pilha de chamadas será imediatamente exibida para restaurar a posição do arquivo salvo e a CALL será abortada.
- Se o rótulo: contiver / ?, a ajuda do GOTO será impressa em vez de procurar o rótulo:. O ponteiro do arquivo não se move, de modo que o código após a CALL seja executado duas vezes, uma vez no contexto CALL e depois novamente após o retorno da CALL. Consulte Por que o CALL imprime a mensagem de ajuda do GOTO neste script e por que o comando depois é executado duas vezes? para mais informações.
- Caso contrário, transfira o controle para o script em lote especificado.
- A execução do rótulo ou script CALLed: continua até que EXIT / B ou final do arquivo seja alcançado; nesse momento, a pilha CALL é exibida e a execução é retomada a partir da posição do arquivo salvo.
A fase 7 não é executada para scripts CALLed ou: labels.
- Caso contrário, o resultado da fase 6 entra na fase 7 para execução.
Fase 7) Execute: O comando é executado
- 7.1 - Executar comando interno - Se o token de comando estiver entre aspas, pule esta etapa. Caso contrário, tente analisar um comando interno e executar.
- Os seguintes testes são feitos para determinar se um token de comando não citado representa um comando interno:
- Se o token de comando corresponder exatamente a um comando interno, execute-o.
-
Caso
+
/
[
]
<space>
<tab>
,
;
contrário, quebre o token de comando antes da primeira ocorrência de ou =
Se o texto anterior for um comando interno, lembre-se desse comando
- Se estiver no modo de linha de comando ou se o comando for de um bloco entre parênteses, se for verdadeiro ou falso, for FOR, ou for envolvido na concatenação de comandos, execute o comando interno
- Caso contrário (deve ser um comando independente no modo em lote), verifique a pasta atual e o PATH em busca de um arquivo .COM, .EXE, .BAT ou .CMD cujo nome base corresponda ao token de comando original
- Se o primeiro arquivo correspondente for .BAT ou .CMD, vá para 7.3.exec e execute esse script
- Caso contrário (a correspondência não encontrada ou a primeira correspondência é .EXE ou .COM), execute o comando interno lembrado
-
Caso
.
\
contrário, quebre o token de comando antes da primeira ocorrência de ou :
Se o texto anterior não for um comando interno, salte para 7.2. Caso contrário,
o texto anterior pode ser um comando interno. Lembre-se deste comando.
- Quebre o token de comando antes da primeira ocorrência de
+
/
[
]
<space>
<tab>
,
;
ou =
Se o texto anterior for o caminho para um arquivo existente, vá para 7.2 ou então
execute o comando interno lembrado.
- Se um comando interno for analisado a partir de um token de comando maior, a parte não utilizada do token de comando será incluída na lista de argumentos
- Só porque um token de comando é analisado como um comando interno não significa que ele será executado com êxito. Cada comando interno possui suas próprias regras sobre como os argumentos e as opções são analisados e qual sintaxe é permitida.
- Todos os comandos internos imprimirão ajuda em vez de desempenhar suas funções se
/?
forem detectados. A maioria reconhece /?
se aparece em algum lugar nos argumentos. Mas alguns comandos, como ECHO e SET, só imprimem ajuda se o primeiro token de argumento começar /?
.
- SET possui algumas semânticas interessantes:
- Se um comando SET tiver uma cotação antes que o nome da variável e as extensões sejam ativadas
set "name=content" ignored
-> value = content
, o texto entre o primeiro sinal de igual e a última cotação será usado como conteúdo (primeira igual e última cotação excluídas). O texto após a última citação é ignorado. Se não houver aspas após o sinal de igual, o restante da linha será usado como conteúdo.
- Se um comando SET não tiver uma citação antes do nome
set name="content" not ignored
-> valor = "content" not ignored
, todo o restante da linha após o igual será usado como conteúdo, incluindo toda e qualquer citação que possa estar presente.
- Uma comparação IF é avaliada e, dependendo se a condição é verdadeira ou falsa, o bloco de comando dependente já analisado apropriado é processado, iniciando na fase 5.
- A cláusula IN de um comando FOR é iterada adequadamente.
- Se este for um FOR / F que itera a saída de um bloco de comando, então:
- A cláusula IN é executada em um novo processo de cmd.exe via CMD / C.
- O bloco de comando deve passar por todo o processo de análise pela segunda vez, mas desta vez em um contexto de linha de comando
- O ECHO iniciará ON, e a expansão atrasada geralmente iniciará desativada (dependendo da configuração do registro)
- Todas as alterações de ambiente feitas pelo bloco de comando da cláusula IN serão perdidas quando o processo filho cmd.exe terminar
- Para cada iteração:
- Os valores da variável FOR são definidos
- O bloco de comando DO já analisado é processado, iniciando na fase 4.
- O GOTO usa a seguinte lógica para localizar o: label
- O rótulo é analisado a partir do primeiro token de argumento
- O script é verificado para a próxima ocorrência do rótulo
- A digitalização começa na posição atual do arquivo
- Se o final do arquivo for alcançado, a varredura retornará ao início do arquivo e continuará até o ponto inicial original.
- A digitalização para na primeira ocorrência do rótulo que encontra e o ponteiro do arquivo é definido para a linha imediatamente após o rótulo. A execução do script continua a partir desse ponto. Observe que um GOTO verdadeiro com êxito abortará imediatamente qualquer bloco de código analisado, incluindo os loops FOR.
- Se o rótulo não for encontrado ou o token do rótulo estiver ausente, o GOTO falhará, uma mensagem de erro será impressa e a pilha de chamadas será exibida. Isso funciona efetivamente como um EXIT / B, exceto que os comandos já analisados no bloco de comando atual que seguem o GOTO ainda são executados, mas no contexto do CALLer (o contexto que existe após EXIT / B)
- Consulte https://www.dostips.com/forum/viewtopic.php?f=3&t=3803 para obter uma descrição mais precisa das regras usadas para analisar rótulos.
- RENAME e COPY aceitam curingas para os caminhos de origem e destino. Mas a Microsoft faz um péssimo trabalho ao documentar como os curingas funcionam, especialmente para o caminho de destino. Um conjunto útil de regras de caracteres curinga pode ser encontrado em Como o comando RENAME do Windows interpreta caracteres curinga?
- 7.2 - Executar alteração de volume - Caso contrário, se o token de comando não começar com uma citação, tiver exatamente dois caracteres e o segundo caractere for dois pontos, altere o volume
- Todos os tokens de argumento são ignorados
- Se o volume especificado pelo primeiro caractere não puder ser encontrado, aborte com um erro
- Um token de comando
::
sempre resultará em um erro, a menos que SUBST seja usado para definir um volume para ::
Se SUBST for usado para definir um volume para ::
, então o volume será alterado, não será tratado como um rótulo.
- 7.3 - Executar comando externo - Caso contrário, tente tratar o comando como um comando externo.
- Se em modo de linha de comando e o comando não é citado e não se inicia com uma especificação de volume, branco-espaço,
,
, ;
, =
ou +
então quebrar o comando token de na primeira ocorrência de <space>
,
;
ou =
e preceder o restante para o argumento símbolo (s).
- Se o segundo caractere do token de comando for dois pontos, verifique se o volume especificado pelo primeiro caractere pode ser encontrado.
Se o volume não puder ser encontrado, aborte com um erro.
- Se no modo de lote e o token de comando começar
:
, vá para 7.4.
Observe que se o token do rótulo começar ::
, isso não será alcançado porque a etapa anterior terá sido interrompida com um erro, a menos que SUBST seja usado para definir um volume ::
.
- Identifique o comando externo a ser executado.
- Esse é um processo complexo que pode envolver o volume atual, o diretório atual, a variável PATH, a variável PATHEXT e / ou as associações de arquivos.
- Se um comando externo válido não puder ser identificado, aborte com um erro.
- Se no modo de linha de comando e o token de comando começar
:
, vá para 7.4.
Observe que isso raramente é alcançado porque a etapa anterior terá sido interrompida com um erro, a menos que o token de comando comece com ::
SUBST e SUBST seja usado para definir um volume para ::
e o token de comando inteiro é um caminho válido para um comando externo.
- 7.3.exec - Execute o comando externo.
- 7.4 - Ignorar um rótulo - Ignore o comando e todos os seus argumentos se o token de comando começar com
:
.
As regras em 7.2 e 7.3 podem impedir que um rótulo atinja esse ponto.
Analisador de Linha de Comando:
Funciona como o BatchLine-Parser, exceto:
Fase 1) Porcentagem de expansão:
- Não
%*
, %1
etc. expansão de argumentos
- Se var for indefinido, ele
%var%
permanecerá inalterado.
- Nenhuma manipulação especial de
%%
. Se var = content, %%var%%
expande para %content%
.
Fase 3) Ecoar o (s) comando (s) analisado (s)
- Isso não é realizado após a fase 2. Somente é executado após a fase 4 para o bloco de comandos FOR DO.
Fase 5) Expansão atrasada: somente se a expansão atrasada estiver ativada
- Se var for indefinido, ele
!var!
permanecerá inalterado.
Fase 7) Executar comando
- Tentativas de CALL ou GOTO a: resultam em um erro.
- Como já documentado na fase 7, um rótulo executado pode resultar em um erro em diferentes cenários.
- Os rótulos executados em lote só podem causar um erro se começarem com
::
- Os rótulos executados pela linha de comando quase sempre resultam em um erro
Análise de valores inteiros
Existem muitos contextos diferentes em que o cmd.exe analisa valores inteiros de seqüências de caracteres e as regras são inconsistentes:
SET /A
IF
%var:~n,m%
(expansão de substring variável)
FOR /F "TOKENS=n"
FOR /F "SKIP=n"
FOR /L %%A in (n1 n2 n3)
EXIT [/B] n
Detalhes para essas regras podem ser encontrados em Regras sobre como o CMD.EXE analisa números
Para quem deseja melhorar as regras de análise do cmd.exe, há um tópico de discussão no fórum do DosTips, no qual os problemas podem ser relatados e as sugestões feitas.
Espero que ajude
Jan Erik (jeb) - Autor original e descobridor de fases
Dave Benham (dbenham) - Muito conteúdo e edição adicionais