Qual estilo de comentário devo usar em arquivos em lotes?

284

Escrevi alguns arquivos em lotes e encontrei este guia do usuário , que foi bastante informativo. Uma coisa que me mostrou foi que as linhas podem ser comentadas não apenas com REM, mas também com ::. Diz:

Os comentários no código do lote podem ser feitos usando dois pontos-e-vírgula; isso é melhor do que o comando REM porque os rótulos são processados ​​antes dos símbolos de redirecionamento. ::<remark>não causa problemas, mas rem <remark>produz erros.

Por que, então, a maioria dos guias e exemplos que vejo usam o REMcomando? Funciona ::em todas as versões do Windows?

MikeFHay
fonte
3
Só para constar, vi problemas quando "REM" é usado para comentar uma linha com redirecionamento no Windows 98.
Digger
6
Como um aparte, de acordo com o comentário do @ Digger: O guia vinculado é para DOS ( command.exe), não para cmd.exeo processador de comandos do NT , conforme encontrado no Windows 2000 em diante. rem <remark>funciona bem neste último (desde pelo menos Windows XP) e REMé a construção oficial e a escolha mais segura em geral; Embora ::tenha suas vantagens, é um hack problemático dentro de (…)blocos (como discutido em muitas respostas aqui).
precisa saber é o seguinte
1
Então, que situação com o REM causa exatamente erros?
TS

Respostas:

360

tl; dr: REM é a maneira documentada e suportada de incorporar comentários em arquivos em lotes.


::é essencialmente um rótulo em branco que nunca pode ser usado, enquanto REMé um comando real que simplesmente não faz nada. Em nenhum dos casos (pelo menos no Windows 7) a presença de operadores de redirecionamento causa problemas.

No entanto, ::é conhecido por se comportar mal em blocos sob certas circunstâncias, sendo analisado não como um rótulo, mas como um tipo de letra de unidade. Estou um pouco confusa sobre onde exatamente, mas isso por si só é suficiente para me fazer usar REMexclusivamente. É a maneira documentada e suportada de incorporar comentários em arquivos em lotes, enquanto ::é apenas um artefato de uma implementação específica.


Aqui está um exemplo em que ::produz um problema em um FORloop.

Este exemplo não funcionará em um arquivo chamado test.batna sua área de trabalho:

@echo off
for /F "delims=" %%A in ('type C:\Users\%username%\Desktop\test.bat') do (
    ::echo hello>C:\Users\%username%\Desktop\text.txt
)
pause

Embora este exemplo funcione como um comentário corretamente:

@echo off
for /F "delims=" %%A in ('type C:\Users\%username%\Desktop\test.bat') do (
    REM echo hello>C:\Users\%username%\Desktop\text.txt
)
pause

O problema parece estar ao tentar redirecionar a saída para um arquivo. Meu melhor palpite é que ele está interpretando ::como uma etiqueta escapada chamada :echo.

Joey
fonte
1
@Firedan: O nome do arquivo em lotes e sua localização são relevantes (junto com o nome e a localização do arquivo para o qual redirecionar?). Caso contrário, seria bom simplificar o exemplo.
Joey
15
Bom toque adicionando um tl; dr
makoshichi 31/05
2
Se houver atraso no uso de variáveis ​​na linha, :: causará algumas mensagens de erro, por exemplo, Não foi possível encontrar o driver de disco específico ..... Então é melhor usar o REM.
Scott Chu
2
:: comentários são analisados ​​e caracteres especiais como> | finalize o comentário e o texto a seguir não será comentado.
Mosh
4
@mosh está certo. Por exemplo, %VAR%variáveis ​​são expandidas. Suponha que você tenha (incorretamente) set TARGET=C:\Program Files (x86)\"foo.exe", e dentro de uma DO(..)expressão que você tenha, :: echo %TARGET%você receberá um erro porque ele (x86)é expandido antes que toda a expressão seja avaliada, levando a uma DO(..)expressão inválida e a erros muito inexplicáveis ​​(neste caso "\ Microsoft era inesperado no momento " ). Você nem precisa |ou está >em sua expressão. A ::não é um comentário real, REMé, no entanto.
Abel
161

Comentários com REM

A REMpode observar uma linha completa, também um cursor de várias linhas no final da linha, se não for o final do primeiro token.

REM This is a comment, the caret is ignored^
echo This line is printed

REM This_is_a_comment_the_caret_appends_the_next_line^
echo This line is part of the remark

O REM seguido por alguns caracteres .:\/=funciona um pouco diferente, ele não comenta um e comercial, então você pode usá-lo como comentário embutido.

echo First & REM. This is a comment & echo second

Mas, para evitar problemas com arquivos existentes como REM, REM.batou REM;.batapenas uma variante modificada deve ser usada.

REM^;<space>Comment

E para o personagem ;também é permitido um dos;,:\/=

O REM é cerca de 6 vezes mais lento que ::(testado no Win7SP1 com 100000 linhas de comentário).
Para um uso normal, isso não é importante (58µs versus 360µs por linha de comentário)

Comentários com ::

A ::sempre executa um cursor de final de linha.

:: This is also a comment^
echo This line is also a comment

Os rótulos e também o rótulo de comentário :: têm uma lógica especial nos blocos de parênteses.
Eles abrangem sempre duas linhas SO: o comando goto não funciona .
Portanto, eles não são recomendados para blocos de parênteses, pois geralmente são a causa de erros de sintaxe.

Com ECHO ONuma REMlinha é mostrada, mas não uma linha comentada com::

Ambos não podem realmente comentar o restante da linha; portanto, um simples %~causará um erro de sintaxe.

REM This comment will result in an error %~ ...

Porém, o REM é capaz de parar o analisador de lote em uma fase inicial, mesmo antes de a fase de caractere especial ser concluída.

@echo ON
REM This caret ^ is visible

Você pode usar & REM ou & :: para adicionar um comentário ao final da linha de comando. Essa abordagem funciona porque '&' introduz um novo comando na mesma linha.

Comentários com sinais de porcentagem% = comment =%

Existe um estilo de comentário com sinais de porcentagem.

Na realidade, essas são variáveis, mas são expandidas para nada.
Mas a vantagem é que eles podem ser colocados na mesma linha, mesmo sem eles &.
O sinal de igual garante que essa variável não possa existir.

echo Mytest
set "var=3"     %= This is a comment in the same line=%

O estilo de porcentagem é recomendado para macros em lote, pois não altera o comportamento do tempo de execução, pois o comentário será removido quando a macro for definida.

set $test=(%\n%
%=Start of code=% ^
echo myMacro%\n%
)
jeb
fonte
2
Deve-se notar que os %=comentários são minuciosos com aspas, ou seja, set foo=bar %=bazresulta em fooexpansão para bar %=baz, como faz set foo="bar" %=baz, enquanto apenas set "foo=bar" %=bazresulta em fooexpansão para barcomo pretendido.
LastStar007
3
@ LastStar007: Vale sempre a set "foo=bar"pena usar o estilo de citação sempre, em geral, porque é a forma mais robusta que delimita claramente o valor. O problema que você está descrevendo é inerente set's comportamento, e não específico para %= … =%comentários: menos que você use "var=val"citando, setconsidera tudo o que segue o =valor, incluindo espaços em branco (até o final da linha ou, se for o caso, o início de o próximo comando embutido).
precisa saber é o seguinte
28

Outra alternativa é expressar o comentário como uma expansão variável que sempre se expande para nada.

Os nomes de variáveis ​​não podem conter =, exceto variáveis ​​dinâmicas não documentadas, como
%=ExitCode%e %=C:%. Nenhum nome de variável pode conter um =após a 1ª posição. Às vezes, uso o seguinte para incluir comentários em um bloco entre parênteses:

::This comment hack is not always safe within parentheses.
(
  %= This comment hack is always safe, even within parentheses =%
)

Também é um bom método para incorporar comentários in-line

dir junk >nul 2>&1 && %= If found =% echo found || %= else =% echo not found

A liderança =não é necessária, mas eu gosto de simetria.

Existem duas restrições:

1) o comentário não pode conter %

2) o comentário não pode conter :

dbenham
fonte
RI MUITO! Torne uma variável superdimensionada! Gênio! %=ExitCode%? Arrumado. Aprenda algo novo todos os dias!
James K
Você implica que a trilha =é necessária. Mas isso não parece ser.
James K
4
@ JamesK - Eu uso o trailing =para que algo como% = ExitCode =% seja um "comentário" e não uma variável dinâmica. Prefiro usar um estilo que sempre funcione (exceto as limitações indicadas na parte inferior da resposta, é claro).
precisa saber é o seguinte
Consulte stackoverflow.com/a/20169219/1689714 para obter uma exploração das variáveis ​​dinâmicas (por exemplo:% = ExitCode%% = ExitCodeAscii%% = C:%% = D:%% __ CD __% etc.), o que elas significam, como elas está definido, etc.
Kieron Hardy
25

Depois que percebi que poderia usar o label ::para fazer comentários e comentar o código, REMparecia-me feio. Como mencionado, o duplo-dois pontos pode causar problemas quando usado dentro de ()código bloqueado, mas eu descobri uma solução alternativa alternando entre os rótulos ::e:space

:: This, of course, does
:: not cause errors.

(
  :: But
   : neither
  :: does
   : this.
)

Não é feio REM, e na verdade adiciona um pouco de estilo ao seu código.

Então, fora dos blocos de código eu uso ::e dentro deles eu alterno entre ::e :.

A propósito, para grandes trechos de comentários, como no cabeçalho do arquivo em lotes, você pode evitar comandos e caracteres especiais completamente, simplesmente gotopassando os comentários. Isso permite que você use qualquer método ou estilo de marcação que desejar, apesar do fato de que, se CMDalguma vez tentasse processar essas linhas, isso causaria um chiado.

@echo off
goto :TopOfCode

=======================================================================
COOLCODE.BAT

Useage:
  COOLCODE [/?] | [ [/a][/c:[##][a][b][c]] INPUTFILE OUTPUTFILE ]

Switches:
       /?    - This menu
       /a    - Some option
       /c:## - Where ## is which line number to begin the processing at.
         :a  - Some optional method of processing
         :b  - A third option for processing
         :c  - A forth option
  INPUTFILE  - The file to process.
  OUTPUTFILE - Store results here.

 Notes:
   Bla bla bla.

:TopOfCode
CODE
.
.
.

Use qualquer notação que desejar *, @etc.

James K
fonte
Como você lida com a /?opção para imprimir este menu?
Hoang
1
@hoang setlocal ENABLEDELAYEDEXPANSION <NEWLINE> conjunto var =% ~ 1 <NEWLINE> o primeiro parâmetro do eco é% 1 <NEWLINE> SE! VAR! == "/?" (GOTO USAGE) <NEWLINE>: USAGE <NEWLINE> echo blá blá .. <NEWLINE>
GL2014 26/13/13
16
Dois pontos alternados e simples devem ser uma dor de cabeça quando você insere ou exclui uma linha.
@ GL2014 basicamente você está dizendo "você não imprime este menu". Seu código de exemplo requer eco de prefixo para cada linha das notas de uso. A resposta de James K é enganosa na medida em que sugere que há alguma maneira de imprimir as notas de uso, conforme escritas.
Timbo
1
@Timbo Eu escrevi uma subrotina ( :PrintHelp) para esta resposta que realmente faz o que @hoang pede. Eu uso <HELP> e </HELP> como marcadores, mas você pode usar o que mais lhe convier.
Cdlvcdlv
21

Esta resposta tenta um resumo pragmático das muitas ótimas respostas nesta página:

A grande resposta de jeb merece menção especial, porque realmente é aprofundada e cobre muitos casos extremos.
Notavelmente, ele ressalta que uma referência de variável / parâmetro mal construída, como %~pode quebrar qualquer uma das soluções abaixo - incluindo REMlinhas .


Comentários de linha inteira - o único estilo diretamente suportado:

  • REM(ou variações de maiúsculas e minúsculas) é o único construto de comentário oficial e é a opção mais segura - veja a resposta útil de Joey .

  • ::é um hack (amplamente utilizado) , que possui prós e contras :


Se você não quiser usar:: , você tem as seguintes opções:

  • Ou : Para estar seguro, faça uma exceção dentro dos (...)blocos e use REM-o ou não coloque comentários dentro (...) .
  • Ou : Memorize as regras dolorosamente restritivas para uso seguro de ::dentro(...) , resumidas no seguinte trecho:
@echo off

for %%i in ("dummy loop") do (

  :: This works: ONE comment line only, followed by a DIFFERENT, NONBLANK line.
  date /t

  REM If you followed a :: line directly with another one, the *2nd* one
  REM would generate a spurious "The system cannot find the drive specified."
  REM error message and potentially execute commands inside the comment.
  REM In the following - commented-out - example, file "out.txt" would be
  REM created (as an empty file), and the ECHO command would execute.
  REM   :: 1st line
  REM   :: 2nd line > out.txt & echo HERE

  REM NOTE: If :: were used in the 2 cases explained below, the FOR statement
  REM would *break altogether*, reporting:
  REM  1st case: "The syntax of the command is incorrect."
  REM  2nd case: ") was unexpected at this time."

  REM Because the next line is *blank*, :: would NOT work here.

  REM Because this is the *last line* in the block, :: would NOT work here.
)

Emulação de outros estilos de comentários - em linha e multilinhas:

Observe que nenhum desses estilos é diretamente suportado pelo idioma do lote , mas pode ser emulado .


Comentários em linha :

* Os trechos de código abaixo são usados vercomo substitutos de um comando arbitrário, para facilitar a experimentação.
* Para fazer com que os SETcomandos funcionem corretamente com comentários embutidos, aspas duplas na name=valuepeça; por exemplo SET "foo=bar",. [1]

Nesse contexto, podemos distinguir dois subtipos:

  • Comentários da EOL ([até o final] da linha), que podem ser colocados após um comando e, invariavelmente, se estendem até o final da linha (novamente, cortesia da resposta de jeb ):

    • ver & REM <comment>tira proveito do fato de que REMé um comando válido e &pode ser usado para colocar um comando adicional após um existente.
    • ver & :: <comment>também funciona, mas (...) é realmente utilizável fora dos blocos , porque seu uso seguro é ainda mais limitado do que o uso ::autônomo.
  • Comentários dentro da linha , que são colocados entre vários comandos em uma linha ou, idealmente, mesmo dentro de um determinado comando.
    Os comentários entre linhas são a forma mais flexível (linha única) e, por definição, também podem ser usados ​​como comentários de EOL.

    • ver & REM^. ^<comment^> & verpermite inserir um comentário entre os comandos (novamente, cortesia da resposta de jeb ), mas observe como <e >precisava ser ^escapado, devido aos seguintes caracteres. não pode ser usado como está:< > | (enquanto sem escape &ou &&ou ||inicia o próximo comando).

    • %= <comment> =%, conforme detalhado na grande resposta de dbenham , é a forma mais flexível , porque pode ser colocada dentro de um comando (entre os argumentos) .
      Ele tira proveito da sintaxe de expansão variável de uma maneira que garante que a expressão sempre se expanda para a cadeia vazia - desde que o texto do comentário contenha nem %nem:
      como REM, %= <comment> =%funcione bem nos (...)blocos externos e internos , mas é mais visualmente distinto; as únicas desvantagens são que é mais difícil digitar, mais fácil cometer erros sintaticamente e pouco conhecido, o que pode dificultar a compreensão do código-fonte que usa a técnica.


Comentários de várias linhas (bloco de linha inteira) :

  • A resposta de James K mostra como usar uma gotodeclaração e um rótulo para delimitar um comentário de várias linhas de tamanho e conteúdo arbitrários (que, no caso dele, ele usa para armazenar informações de uso).

  • A resposta de Zee mostra como usar um "rótulo nulo" para criar um comentário de várias linhas, embora seja necessário tomar cuidado para terminar com todas as linhas internas ^.

  • Rob van der post do Woude menciona outra opção um tanto obscuro que lhe permite terminar um arquivo com um número arbitrário de linhas de comentário : An abertura (única faz com que tudo o que vem depois a ser ignorado , desde que ele não contém um (não ^-escapado) ), ou seja, desde que o bloco não esteja fechado .


[1] Usar SET "foo=bar"para definir variáveis ​​- ou seja, colocar aspas duplas em torno do nome e =do valor combinado - é necessário em comandos como SET "foo=bar" & REM Set foo to bar., para garantir que o que segue o valor da variável pretendido (até o próximo comando, neste caso) um único espaço) acidentalmente não faz parte dele.
(Como um aparte: SET foo="bar"não apenas evitaria o problema, faria as aspas duplas parte do valor ).
Nota que este problema é inerente ao SETe até mesmo se aplica aos acidental espaços em branco após o valor, por isso é aconselhável sempre usar a SET "foo=bar"abordagem.

mklement0
fonte
7

Esta página informa que o uso de "::" será mais rápido sob certas restrições Apenas uma coisa a considerar ao escolher

mishal153
fonte
2
Isto é verdade, pelo menos para Win7SP1, ::pode ser 6 vezes mais rápido do queREM
jeb
4

boa pergunta ... Estou procurando essa funcionalidade há muito tempo ...

depois de vários testes e truques, parece que a melhor solução é a mais óbvia ...

-> a melhor maneira de fazer isso, impedindo a integridade do analisador falhar, é reutilizando o REM:

echo this will show until the next REM &REM this will not show

você também pode usar várias linhas com o truque "NULL LABEL" ... (não esqueça o ^ no final da linha para obter continuidade)

::(^
this is a multiline^
comment... inside a null label!^
dont forget the ^caret at the end-of-line^
to assure continuity of text^ 
)
ZEE
fonte
3

James K, desculpe-me por estar errado em boa parte do que disse. O teste que fiz foi o seguinte:

@ECHO OFF
(
  :: But
   : neither
  :: does
   : this
  :: also.
)

Isso atende à sua descrição de alternância, mas falha com um ") era inesperado no momento". mensagem de erro.

Fiz alguns testes hoje e descobri que alternar não é a chave, mas parece que a chave está com um número par de linhas, sem duas linhas seguidas começando com dois pontos (: :) e não terminando com dois pontos . Considere o seguinte:

@ECHO OFF
(
   : But
   : neither
   : does
   : this
   : cause
   : problems.
)

Isso funciona!

Mas considere também isso:

@ECHO OFF
(
   : Test1
   : Test2
   : Test3
   : Test4
   : Test5
   ECHO.
)

A regra de ter um número par de comentários não parece se aplicar ao finalizar um comando.

Infelizmente, isso é apenas o suficiente para que eu não tenha certeza se quero usá-lo.

Realmente, a melhor solução e a mais segura que consigo pensar é se um programa como o Notepad ++ ler REM como dois pontos e depois escrever dois pontos novamente como instruções REM quando o arquivo for salvo. Mas não conheço esse programa e não conheço nenhum plug-in para o Notepad ++ que faça isso também.

Darin
fonte
2

Uma discussão muito detalhada e analítica sobre o tema está disponível on ESTE página

Possui os códigos de exemplo e os prós / contras de diferentes opções.

BiLaL
fonte
1
Você deve resumir o conteúdo dos links fornecidos nas respostas. Caso contrário, é chamado de "resposta apenas ao link" e é completamente inútil se o link desaparecer. Neste caso, a página apontada é bastante bem-humorado em que faz a sua escolha com base na otimização de velocidade de leitura de arquivos em lote a partir de disquete lento :)
GreenAsJade
0

Existem várias maneiras de comentar em um arquivo em lotes

1) Usando rem

Esta é a maneira oficial. Aparentemente, leva mais tempo para ser executado do que ::, embora aparentemente pare de analisar mais cedo, antes que os sinais de intercalação sejam processados. A expansão percentual ocorre antes do rem e ::é identificada; portanto, o percentual incorreto de uso, ou seja %~, causará erros se houver porcentagens. Seguro para usar em qualquer lugar nos blocos de código.

2) O uso de etiquetas :, ::ou :;etc.

Para :: comment, ': comment' é um nome de rótulo inválido porque começa com um caractere inválido. Não há problema em usar dois pontos no meio de um rótulo. Se um espaço começa no início da etiqueta, ele é removido : labeltorna-se :label. Se um espaço ou dois pontos aparecer no meio do rótulo, o restante do nome não será interpretado, o que significa que, se houver dois rótulos :f:ooe :f rr, ambos serão interpretados como :fe somente o rótulo definido posteriormente no arquivo será saltado. O restante do rótulo é efetivamente um comentário. Existem várias alternativas para ::, listadas aqui . Você nunca pode gotoou callum ::foorótulo. goto :fooe goto ::foonão vai funcionar.

Eles funcionam bem fora dos blocos de código, mas após um rótulo em um bloco de código, inválido ou não, deve haver uma linha de comando válida. :: commenté de fato outro comando válido. Ele interpreta isso como um comando e não como um rótulo; o comando tem precedência. Qual é o comando para cd no ::volume, que funcionará se você tiver executado subst :: C:\, caso contrário, você receberá um erro de volume não encontrado. É por isso que :;é discutivelmente melhor porque não pode ser interpretado dessa maneira e, portanto, é interpretado como um rótulo, que serve como um comando válido. Isso não é recursivo, ou seja, o próximo rótulo não precisa de um comando depois dele. É por isso que eles vêm em dois.

Você precisa fornecer um comando válido após o rótulo, por exemplo echo something. Um rótulo em um bloco de código precisa vir com pelo menos um comando válido, portanto as linhas vêm em pares de dois. Você receberá um )erro inesperado se houver um espaço ou um parêntese de fechamento na próxima linha. Se houver um espaço entre as duas ::linhas, você receberá um erro de sintaxe inválido.

Você também pode usar o operador de sinal de intercalação no ::comentário da seguinte forma:

@echo off

echo hello
(
   :;(^
   this^
   is^
   a^
   comment^
   )
   :;
)
   :;^
   this^
   is^
   a^
   comment
   :;
) 

Mas você precisa do final :;pelo motivo indicado acima.

@echo off

(
echo hello
:;
:; comment
:; comment
:;
)
echo hello

Tudo bem, desde que haja um número par. Esta é sem dúvida a melhor maneira de comentar - com 4 linhas e :;. Com :;você, não há erros que precisam ser suprimidos usando 2> nulou subst :: C:\. Você pode usar subst :: C:\para fazer com que o erro de volume não encontrado desapareça, mas isso significa que você também precisará colocar C: no código para impedir que seu diretório de trabalho se torne ::\.

Para comentar no final de uma linha, você pode fazer command &::ou command & rem comment, mas ainda deve haver um número par, assim:

@echo off

(
echo hello & :;yes
echo hello & :;yes
:;
)

echo hello

O primeiro echo hello & :;yestem um comando válido na próxima linha, mas o segundo & :;yesnão, então ele precisa de um, ou seja, o :;.

3) Usando uma variável de ambiente inválida

%= comment =%. Em um arquivo em lotes, as variáveis ​​de ambiente que não são definidas são removidas do script. Isso torna possível usá-los no final de uma linha sem usar &. É personalizado usar uma variável de ambiente inválida, ou seja, uma que contenha um sinal de igual. O igual extra não é necessário, mas faz com que pareça simétrico. Além disso, nomes de variáveis ​​iniciados com "=" são reservados para variáveis ​​dinâmicas não documentadas. Essas variáveis ​​dinâmicas nunca terminam com "=", portanto, usando um "=" no início e no final do comentário, não há possibilidade de conflito de nome. O comentário não pode conter %ou :.

@echo off 
echo This is an example of an %= Inline Comment =% in the middle of a line.

4) Como um comando, redirecionando stderr para nul

@echo off
(
echo hello
;this is a comment 2> nul
;this is another comment  2> nul
)

5) No final de um arquivo, tudo depois de um parêntese não fechado é um comentário

@echo off
(
echo hello
)

(this is a comment
this is a comment
this is a comment
Lewis Kelsey
fonte