Encontrei o ss64.com, que fornece uma boa ajuda sobre como escrever scripts em lote que o Windows Command Interpreter executará.
No entanto, não consegui encontrar uma boa explicação sobre a gramática dos scripts em lote, como as coisas se expandem ou não e como escapar delas.
Aqui estão alguns exemplos de perguntas que não consegui resolver:
- Como o sistema de cotação é gerenciado? Eu criei um script TinyPerl
(foreach $i (@ARGV) { print '*' . $i ; }
), compilei e chamei assim:my_script.exe "a ""b"" c"
→ a saída é*a "b*c
my_script.exe """a b c"""
→ produzi-lo*"a*b*c"
- Como o
echo
comando interno funciona? O que é expandido dentro desse comando? - Por que preciso usar
for [...] %%I
em scripts de arquivo, masfor [...] %I
em sessões interativas? - Quais são os caracteres de escape e em que contexto? Como escapar de um sinal de porcentagem? Por exemplo, como posso ecoar
%PROCESSOR_ARCHITECTURE%
literalmente? Descobri queecho.exe %""PROCESSOR_ARCHITECTURE%
funciona, existe uma solução melhor? - Como pares de
%
partida? Exemplo:set b=a
,echo %a %b% c%
→%a a c%
set a =b
,echo %a %b% c%
→bb c%
- Como garantir que uma variável passe para um comando como argumento único, se essa variável contiver aspas duplas?
- Como as variáveis são armazenadas ao usar o
set
comando? Por exemplo, se eu façoset a=a" b
e entãoecho.%a%
obtenhoa" b
. No entanto, se eu usarecho.exe
o UnxUtils, receboa b
. Como vem a%a%
expansão de uma maneira diferente?
Obrigado por suas luzes.
Respostas:
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>
.<Ctrl-Z>
(0x1A) é lido como<LF>
(LineFeed 0x0A)<Ctrl-Z>
, é tratado como si - é não convertida em<LF>
Fase 1) Porcentagem de expansão:
%%
é substituído por um único%
%*
,%1
,%2
, etc.)%var%
, se var não existir, substitua-o por nada<LF>
não dentro da%var%
expansãoFase 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.
<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
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:
<CR>
seguida, remova-o, como se nunca estivesse lá (exceto pelo comportamento de redirecionamento estranho )^
), o próximo caractere é escapado e o cursor de intercalação é removido. Caracteres escapados perdem todo significado especial (exceto<LF>
)."
), 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>
.<LF>
<LF>
é despojado<LF>
, ele será tratado como um literal, o que significa que esse processo não é recursivo.<LF>
entre parênteses<LF>
é retirado e a análise da linha atual é encerrada.<LF>
dentro de um bloco entre parênteses FOR IN<LF>
é convertido em um<space>
<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.&
|
<
ou>
, dividir a linha neste ponto, a fim de manipular pipes, concatenação de comandos e redirecionamento.|
), cada lado é um comando (ou bloco de comando) separado que recebe tratamento especial na fase 5.3&
,&&
ou||
concatenação de comando, cada lado da concatenação é tratado como um comando separado.<
,<<
,>
, 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.@
, ele@
terá um significado especial. (@
não é especial em nenhum outro contexto)@
é removido.@
antes de uma abertura(
, todo o bloco entre parênteses é excluído do eco da fase 3.(
não será especial.(
, inicie uma nova instrução composta e aumente o contador de parênteses)
encerre a instrução composta e diminua o contador de parênteses.)
funcionará de maneira semelhante a umaREM
instrução, desde que seja imediatamente seguido por um delimitador de token, caractere especial, nova linha ou fim de arquivo^
(é possível concatenação de linha)@
é retirado e o redirecionamento movido para o final).(
funciona como um delimitador de token de comando, além dos delimitadores de token padrão<LF>
como<space>
. Após a análise da cláusula IN, todos os tokens são concatenados juntos para formar um único token.^
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^
.:
e esta for a primeira rodada da fase 2 (não uma reinicialização devido a CALL na fase 6),)
,<
,>
,&
e|
já não têm significado especial. O restante da linha é considerado parte do rótulo "comando".^
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.(
não tem mais um significado especial para o primeiro comando que segue o Rótulo Não Executado .|
tubo ou&
,&&
ou||
concatenação de comando na linha.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.%%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.~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.---- 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).
!
. 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:^
), o próximo caractere não tem significado especial, o próprio intercalação é removido!
é recolhida em um único!
!
é removido<CR>
ou<LF>
)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.
%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.<LF>
com um comando antes e depois serão convertidos em<space>&
. Outros<LF>
são despidos.Fase 5.5) Executar redirecionamento: Qualquer redirecionamento descoberto na fase 2 agora é executado.
||
seja usado .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.
/?
. 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.CALL
, para que várias CALLs possam ser empilhadas&
ou|
(
@
IF
ouFOR
não é reconhecido como um comando interno ou externo.:
.:
,A fase 7 não é executada para scripts CALLed ou: labels.
Fase 7) Execute: O comando é executado
+
/
[
]
<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
.
\
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.
+
/
[
]
<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.
/?
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 "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.
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.
::
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.,
,;
,=
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 volume não puder ser encontrado, aborte com um erro.
:
, 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::
.:
, 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.:
.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:
%*
,%1
etc. expansão de argumentos%var%
permanecerá inalterado.%%
. Se var = content,%%var%%
expande para%content%
.Fase 3) Ecoar o (s) comando (s) analisado (s)
Fase 5) Expansão atrasada: somente se a expansão atrasada estiver ativada
!var!
permanecerá inalterado.Fase 7) Executar comando
::
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
fonte
)
realmente funciona quase como umREM
comando quando o contador parêntese é 0. Tente ambos a partir da linha de comando:) Ignore this
eecho OK & ) Ignore this
Ao invocar um comando a partir de uma janela de comando, a tokenização dos argumentos da linha de comando não é realizada por
cmd.exe
(também conhecido como "o shell"). Geralmente, a tokenização é feita pelo tempo de execução C / C ++ dos processos recém-formados, mas isso não é necessariamente o caso - por exemplo, se o novo processo não foi gravado em C / C ++ ou se o novo processo optar por ignorarargv
e processar a linha de comando bruta para si mesma (por exemplo, com GetCommandLine ()) No nível do sistema operacional, o Windows passa linhas de comando simbolizadas como uma única sequência para novos processos. Isso contrasta com a maioria dos shells * nix, onde o shell simboliza os argumentos de maneira consistente e previsível antes de passá-los para o processo recém-formado. Tudo isso significa que você pode experimentar um comportamento de tokenização de argumento bastante divergente em diferentes programas no Windows, pois programas individuais geralmente levam a tokenização de argumento em suas próprias mãos.Se parece anarquia, é o que é. No entanto, como um grande número de programas do Windows utiliza o tempo de execução do Microsoft C / C ++
argv
, pode ser útil entender como o MSVCRT tokeniza argumentos. Aqui está um trecho:A "linguagem de lote" da Microsoft (
.bat
) não é exceção a esse ambiente anárquico e desenvolveu suas próprias regras exclusivas para tokenização e escape. Também parece que o prompt de comando do cmd.exe realiza algum pré-processamento do argumento da linha de comandos (principalmente para substituição e escape de variáveis) antes de passar o argumento para o processo que está sendo executado recentemente. Você pode ler mais sobre os detalhes de baixo nível do idioma do lote e do cmd escapando nas excelentes respostas de jeb e dbenham nesta página.Vamos criar um simples utilitário de linha de comando em C e ver o que diz sobre seus casos de teste:
(Notas: argv [0] é sempre o nome do executável e é omitido abaixo por questões de brevidade. Testado no Windows XP SP3. Compilado com o Visual Studio 2005.)
E alguns dos meus próprios testes:
fonte
[a "b" c]
poderia se tornar o[a "b] [c]
pós-processamento.GetCommandLine
. Talvez o TinyPerl esteja ignorando o argv e simplesmente tokenizando a linha de comando bruta por suas próprias regras.Regras de porcentagem de expansão
Aqui está uma explicação expandida da Fase 1 na resposta do jeb (válida para o modo em lote e o modo de linha de comando).
Fase 1) Porcentagem de expansão A partir da esquerda, procure cada caractere em busca de
%
ou<LF>
. Se encontrado, então<LF>
)<LF>
então<LF>
partir de<CR>
)%
, então vá para 1.1%
) ignorado se o modo de linha de comando%
,substitua
%%
por um%
e continue a digitalização*
extensões seguidas e de comando estiverem ativadas,substitua
%*
pelo texto de todos os argumentos da linha de comando (Substitua por nada se não houver argumentos) e continue a varredura.<digit>
, em seguida,substituir
%<digit>
com valor de argumento (substitua com nada se não for definido) e continuar digitalização.~
extensões seguidas e de comando estiverem ativadas,<digit>
,substitua
%~[modifiers]<digit>
pelo valor do argumento modificado (substitua por nada se não estiver definido ou se especificado $ PATH: o modificador não estiver definido) e continue a varredura.Nota: os modificadores não diferenciam maiúsculas de minúsculas e podem aparecer várias vezes em qualquer ordem, exceto $ PATH: o modificador pode aparecer apenas uma vez e deve ser o último modificador antes do
<digit>
observe a próxima sequência de caracteres, quebrando antes
%
ou no final do buffer e chame-os de VAR (pode ser uma lista vazia)%
, em seguida,substitua
%VAR%
pelo valor de VAR e continue a varreduraremova
%VAR%
e continue a digitalizaçãoa próxima sequência de caracteres, quebrando antes
%
:
ou no final do buffer, e chame-os de VAR (pode ser uma lista vazia). Se o VAR quebrar antes:
e o caractere subsequente for%
incluído:
como o último caractere no VAR e quebrar antes%
.%
, em seguida,substitua
%VAR%
pelo valor de VAR e continue a varreduraremova
%VAR%
e continue a digitalização:
entãoremova
%VAR:
e continue a digitalização.~
então[integer][,[integer]]%
,substitua
%VAR:~[integer][,[integer]]%
por substring do valor de VAR (possivelmente resultando em sequência vazia) e continue a varredura.=
ou*=
entãobusca variável inválido e substituir sintaxe levanta erro fatal: Todos analisado comandos são abortados, e processamento em lote aborta se na modalidade de grupo!
[*]search=[replace]%
, onde a pesquisa pode incluir qualquer conjunto de caracteres=
, exceto , e replace pode incluir qualquer conjunto de caracteres%
, exceto ,Substitua
%VAR:[*]search=[replace]%
pelo valor de VAR após executar a pesquisa e a substituição (possivelmente resultando em uma sequência vazia) e continue Varreduraremova
%
e continue a digitalização começando com o próximo caractere após o%
%
e continue a varredura começando com o próximo caractere após a liderança preservada%
O texto acima ajuda a explicar por que esse lote
Dá estes resultados:
Nota 1 - A fase 1 ocorre antes do reconhecimento das instruções REM. Isso é muito importante porque significa que mesmo uma observação pode gerar um erro fatal se tiver sintaxe de expansão de argumento inválida ou pesquisa de variável inválida e substituir a sintaxe!
Nota 2 - Outra consequência interessante das regras de análise de%: Variáveis que contêm: no nome podem ser definidas, mas não podem ser expandidas, a menos que as extensões de comando estejam desabilitadas. Há uma exceção - um nome de variável que contém dois pontos no final pode ser expandido enquanto as extensões de comando estão ativadas. No entanto, você não pode executar substring ou procurar e substituir operações em nomes de variáveis que terminam com dois pontos. O arquivo em lotes abaixo (cortesia da jeb) demonstra esse comportamento
Nota 3 - Um resultado interessante da ordem das regras de análise que jeb apresenta em seu post: Ao executar localizar e substituir por expansão atrasada, caracteres especiais nos termos de localização e substituição devem ser escapados ou citados. Mas a situação é diferente para a expansão percentual - o termo de busca não deve ser escapado (embora possa ser citado). A porcentagem de substituição de string pode ou não exigir escape ou citação, dependendo da sua intenção.
Regras de expansão atrasada
Aqui está uma explicação expandida e mais precisa da fase 5 na resposta de jeb (válida para o modo em lote e o modo de linha de comando)
Fase 5) Expansão atrasada
Essa fase é ignorada se qualquer uma das seguintes condições se aplicar:
CALL
bloco entre parênteses, a qualquer forma de concatenação de comando (&
,&&
ou||
) ou a um canal|
.O processo de expansão atrasada é aplicado aos tokens independentemente. Um comando pode ter vários tokens:
for ... in(TOKEN) do
if defined TOKEN
if exists TOKEN
if errorlevel TOKEN
if cmdextversion TOKEN
if TOKEN comparison TOKEN
, Em que a comparação é um de==
,equ
,neq
,lss
,leq
,gtr
, ougeq
Nenhuma alteração é feita nos tokens que não contêm
!
.Para cada token que contém pelo menos um
!
, verifique cada caractere da esquerda para a direita em busca de^
ou!
, e se encontrado,!
ou^
literais^
então^
!
, entãoobserve a próxima sequência de caracteres, quebrando antes
!
ou<LF>
e chame-os de VAR (pode ser uma lista vazia)!
, em seguida,substitua
!VAR!
pelo valor de VAR e continue a varreduraremova
!VAR!
e continue a digitalizaçãoprocure na próxima sequência de caracteres, quebrando antes
!
,:
ou<LF>
, e chamá-los VAR (pode ser uma lista vazia). Se o VAR quebrar antes:
e o caractere subsequente for!
incluído:
como o último caractere no VAR e quebrar antes!
!
, em seguida,substitua
!VAR!
pelo valor VAR e continue a varreduraremova
!VAR!
e continue a digitalização:
entãoremova
!VAR:
e continue a digitalização~
então[integer][,[integer]]!
, substitua!VAR:~[integer][,[integer]]!
por substring do valor de VAR (possivelmente resultando em sequência vazia) e continue a varredura.[*]search=[replace]!
, onde a pesquisa pode incluir qualquer conjunto de caracteres=
, exceto , e replace pode incluir qualquer conjunto de caracteres!
, exceto ,Substitua
!VAR:[*]search=[replace]!
pelo valor de VAR após executar a pesquisa e a substituição (possivelmente resultando em uma sequência vazia) e continuar a digitalização!
Else principal, preserve o líder
!
!
fonte
%definedVar:a=b%
vs%undefinedVar:a=b%
e as%var:~0x17,-010%
formas%<digit>
,%*
ou%~
. E o comportamento muda para variáveis indefinidas. Talvez você precisa para abrir uma segunda respostaConforme indicado, os comandos passam toda a cadeia de argumentos em μSoft land, e cabe a eles analisá-los em argumentos separados para seu próprio uso. Não há consistência nisso entre diferentes programas e, portanto, não há um conjunto de regras para descrever esse processo. Você realmente precisa verificar cada caixa de canto para qualquer biblioteca C que seu programa use.
No que diz respeito aos
.bat
arquivos do sistema , aqui está esse teste:Agora podemos executar alguns testes. Veja se você consegue descobrir exatamente o que a μSoft está tentando fazer:
Tudo bem até agora. (Vou deixar de fora o desinteressante
%cmdcmdline%
e%0
de agora em diante.)Nenhuma expansão de nome de arquivo.
Nenhuma remoção de cotação, embora as aspas impeçam a divisão de argumentos.
As aspas duplas consecutivas fazem com que percam quaisquer habilidades especiais de análise que possam ter. @ Exemplo de Beniot:
Quiz: Como você passa o valor de qualquer ambiente var como um único argumento (ou seja, como
%1
) para um arquivo bat?A análise sã parece interrompida para sempre.
Para o seu entretenimento, tente adicionar diversos
^
,\
,'
,&
(& c.) Caracteres a estes exemplos.fonte
t
éa "b c
. Você tem uma receita para obter esses 6 caracteres (a
, 2 × espaço,"
,b
, ec
) para aparecer como%1
dentro de um.cmd
? Eu gosto do seu pensamento embora.args "%t:"=""%"
é muito perto :-)Você já tem ótimas respostas acima, mas para responder uma parte da sua pergunta:
O que está acontecendo lá é que, como você tem um espaço antes de =, uma variável é criada, chamada
%a<space>%
quando vocêecho %a %
é avaliado corretamente comob
.A parte restante
b% c%
é então avaliada como texto simples + uma variável indefinida% c%
, o que deve ser feito eco como digitado, para mimecho %a %b% c%
retornosbb% c%
Suspeito que a capacidade de incluir espaços nos nomes de variáveis seja mais uma supervisão do que um 'recurso' planejado
fonte
editar: veja a resposta aceita, o que segue está errado e explica apenas como passar uma linha de comando para o TinyPerl.
Em relação a aspas, tenho a sensação de que o comportamento é o seguinte:
"
é encontrado, o globbing das cordas começa"
é um é globbed"
é encontrado:""
(portanto, um triplo"
), uma aspas duplas será adicionada à string"
(assim, um duplo"
), uma aspas dupla será adicionada às cordas e às extremidades das cordas"
, o globbing da corda terminaEm resumo:
"a """ b "" c"""
consiste em duas strings:a " b "
ec"
"a""
,"a"""
e"a""""
são todos da mesma sequência se no final de uma linhafonte
Observe que a Microsoft publicou o código-fonte do seu terminal. Pode funcionar de maneira semelhante à linha de comando em relação à análise de sintaxe. Talvez alguém esteja interessado em testar as regras de análise de engenharia reversa de acordo com as regras de análise do terminal.
Link para o código fonte.
fonte