¿Qué estilo de comentario debo usar en los archivos por lotes?

284

He estado escribiendo algunos archivos por lotes, y me encontré con esta guía del usuario , que ha sido bastante informativa. Una cosa que me mostró fue que las líneas se pueden comentar no solo con REM, sino también con ::. Dice:

Los comentarios en el código de lote se pueden hacer usando dos puntos dobles, esto es mejor que usar el comando REM porque las etiquetas se procesan antes de los símbolos de redireccionamiento. ::<remark>no causa problemas pero rem <remark>produce errores.

¿Por qué entonces, la mayoría de las guías y ejemplos que veo usan el REMcomando? ¿ ::Funciona en todas las versiones de Windows?

MikeFHay
fuente
3
Solo para que conste, he visto problemas cuando se usa "REM" para comentar una línea con redireccionamiento en Windows 98.
Digger
66
Como comentario aparte, en línea con el comentario de @ Digger: La guía vinculada es para DOS ( command.exe), no para cmd.exeel procesador de comandos NT como se encuentra en Windows 2000 en adelante. rem <remark>funciona bien en este último (desde al menos Windows XP), y REMes la restricción oficial y la opción más segura en general; Si bien ::tiene sus ventajas, en última instancia es un truco que es problemático dentro de los (…)bloques (como se discute en muchas respuestas aquí).
mklement0
1
Entonces, ¿qué situación con REM causa errores exactamente?
TS

Respuestas:

360

tl; dr: REM es la forma documentada y compatible de incrustar comentarios en archivos por lotes.


::es esencialmente una etiqueta en blanco a la que nunca se puede saltar, mientras que REMes un comando real que simplemente no hace nada. En ninguno de los casos (al menos en Windows 7) la presencia de operadores de redireccionamiento causa un problema.

Sin embargo, ::se sabe que se comportan mal en bloques bajo ciertas circunstancias, siendo analizados no como una etiqueta sino como una especie de letra de unidad. Estoy un poco confuso sobre dónde exactamente, pero eso solo es suficiente para hacerme usar REMexclusivamente. Es la forma documentada y compatible de incrustar comentarios en archivos por lotes, mientras que ::es simplemente un artefacto de una implementación particular.


Aquí hay un ejemplo donde se ::produce un problema en un FORbucle.

Este ejemplo no funcionará en un archivo llamado test.baten su escritorio:

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

Si bien este ejemplo funcionará correctamente como comentario:

@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

El problema parece ser al intentar redirigir la salida a un archivo. Mi mejor suposición es que se está interpretando ::como una etiqueta escapada llamada :echo.

Joey
fuente
1
@Firedan: ¿Es relevante el nombre del archivo por lotes y su ubicación (junto con el nombre y la ubicación del archivo al que se debe redirigir?). De lo contrario, sería bueno simplificar el ejemplo.
Joey
15
Buen toque agregando un tl; dr
makoshichi
2
Si hay un retraso en el uso de la variable en línea, :: causará algunos mensajes de error, por ejemplo, no se puede encontrar un controlador de disco específico ... Entonces, mejor usar REM.
Scott Chu
2
:: los comentarios se analizan y los caracteres especiales como> | finaliza el comentario, y el siguiente texto no está comentado.
mosh
44
@mosh tiene razón. Por ejemplo, las %VAR%variables se expanden. Suponga que tiene (incorrectamente) set TARGET=C:\Program Files (x86)\"foo.exe", y dentro de una DO(..)expresión que tiene :: echo %TARGET%obtendrá un error porque (x86)se expande antes de que se evalúe toda la expresión, lo que lleva a una DO(..)expresión no válida y errores muy inexplicables (en este caso "\ Microsoft fue inesperado en este momento " ). Ni siquiera necesitas |o >en tu expresión. Sin embargo, A ::no es un comentario real REM.
Abel
161

Comentarios con REM

A REMpuede remarcar una línea completa, también un cursor multilínea al final de la línea, si no es el final del primer 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

REM seguido de algunos caracteres .:\/=funciona un poco diferente, no comenta un ampersand, por lo que puede usarlo como comentario en línea.

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

Pero para evitar problemas con archivos existentes como REM, REM.bato REM;.batsolo se debe usar una variante modificada.

REM^;<space>Comment

Y para el personaje ;también está permitido uno de;,:\/=

REM es aproximadamente 6 veces más lento que ::(probado en Win7SP1 con 100000 líneas de comentarios).
Para un uso normal no es importante (58 µs versus 360 µs por línea de comentario)

Comentarios con ::

A ::siempre ejecuta un cursor de fin de línea.

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

Las etiquetas y también la etiqueta de comentario :: tienen una lógica especial en los bloques de paréntesis.
Abarcan siempre dos líneas SO: el comando goto no funciona .
Por lo tanto, no se recomiendan para bloques de paréntesis, ya que a menudo son la causa de los errores de sintaxis.

Con ECHO ONuna REMlínea se muestra, pero no una línea comentada con::

Ambos realmente no pueden comentar el resto de la línea, por lo que un simple %~causará un error de sintaxis.

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

Pero REM puede detener el analizador por lotes en una fase temprana, incluso antes de que se complete la fase de caracteres especiales.

@echo ON
REM This caret ^ is visible

Puede usar & REM o & :: para agregar un comentario al final de la línea de comando. Este enfoque funciona porque '&' introduce un nuevo comando en la misma línea.

Comentarios con signos de porcentaje% = comentario =%

Existe un estilo de comentario con signos de porcentaje.

En realidad, estas son variables pero se expanden a la nada.
Pero la ventaja es que se pueden colocar en la misma línea, incluso sin ella &.
El signo igual asegura que tal variable no pueda existir.

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

El estilo de porcentaje se recomienda para macros por lotes, ya que no cambia el comportamiento del tiempo de ejecución, ya que el comentario se eliminará cuando se defina la macro.

set $test=(%\n%
%=Start of code=% ^
echo myMacro%\n%
)
jeb
fuente
2
Debe tenerse en cuenta que %=los comentarios son meticulosos entre comillas, es decir, set foo=bar %=bazlos resultados en foola ampliación a bar %=baz, como lo hace set foo="bar" %=baz, mientras que sólo set "foo=bar" %=bazda lugar a foola ampliación de barla forma prevista.
LastStar007
3
@ LastStar007: Siempre set "foo=bar"vale la pena recomendar usar el estilo de comillas en general, porque es la forma más robusta que delimita claramente el valor. El tema que usted está describiendo es inherente set's comportamiento, y no es específico de %= … =%los comentarios: A menos que utilice "var=val"citar, setconsidera todo lo que sigue el =valor, incluyendo espacios en blanco (hasta el final de la línea o, en su caso, el inicio de el siguiente comando en línea).
mklement0
28

Otra alternativa es expresar el comentario como una expansión variable que siempre se expande a nada.

Los nombres de las variables no pueden contener =, excepto las variables dinámicas no documentadas como
%=ExitCode%y %=C:%. Ningún nombre de variable puede contener un =después de la primera posición. Así que a veces uso lo siguiente para incluir comentarios dentro de un bloque entre paréntesis:

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

También es un buen método para incorporar comentarios en línea.

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

La guía =no es necesaria, pero me gusta si es por la simetría.

Hay dos restricciones:

1) el comentario no puede contener %

2) el comentario no puede contener :

dbenham
fuente
Jajaja ¡Conviértalo en una variable de gran tamaño! ¡Genio! %=ExitCode%? Ordenado. ¡Aprenda algo nuevo cada día!
James K
Usted implica que el seguimiento =es necesario. Pero no parece ser.
James K
44
@JamesK: uso el seguimiento =para que algo como% = ExitCode =% sea un "comentario" y no una variable dinámica. Prefiero usar un estilo que siempre funcione (a excepción de las limitaciones indicadas al final de la respuesta, por supuesto).
dbenham
Consulte stackoverflow.com/a/20169219/1689714 para una exploración de las variables dinámicas (por ejemplo,% = ExitCode%% = ExitCodeAscii%% = C:%% = D:%% __ CD __% etc.), qué significan, cómo están configurados, etc.
Kieron Hardy
25

Después de darme cuenta de que podía usar la etiqueta ::para hacer comentarios y comentar el código, REMsimplemente me pareció feo. Como se ha mencionado, el doble punto puede causar problemas cuando se usa dentro del ()código bloqueado, pero he descubierto una solución alternativa al alternar entre las etiquetas ::y:space

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

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

No es feo REM, y en realidad agrega un poco de estilo a su código.

Entonces, fuera de los bloques de código que uso ::y dentro de ellos alterno entre ::y :.

Por cierto, para grandes trozos de comentarios, como en el encabezado de su archivo por lotes, puede evitar comandos y caracteres especiales por completo simplemente gotosobre sus comentarios. Esto le permite utilizar cualquier método o estilo de marcado que desee, a pesar de que si CMDalguna vez tratara de procesar esas líneas, arrojaría un silbido.

@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
.
.
.

Usa cualquier notación que desees *, @etc.

James K
fuente
¿Cómo manejas el /?interruptor para que imprima este menú?
hoang
1
@hoang setlocal ENABLEDELAYEDEXPANSION <NEWLINE> set var =% ~ 1 <NEWLINE> echo first param is% 1 <NEWLINE> IF! VAR! == "/?" (GOTO USAGE) <NEWLINE>: USAGE <NEWLINE> echo blah blah .. <NEWLINE>
GL2014
16
Alternar dos puntos simples y dobles debe ser un dolor de cabeza al insertar o eliminar una fila.
@ GL2014 básicamente estás diciendo " no imprimes este menú". Su código de ejemplo requiere el prefijo echo a cada línea de las notas de uso. La respuesta de James K es engañosa en la medida en que sugiere que hay alguna forma de imprimir las notas de uso tal como están escritas.
Timbo
1
@Timbo Escribí una subrutina ( :PrintHelp) para esta respuesta que de hecho hace lo que @hoang pide. Yo uso <HELP> y </HELP> como marcadores pero puedes usar lo que te convenga.
cdlvcdlv
21

Esta respuesta intenta un resumen pragmático de las muchas excelentes respuestas en esta página:

La gran respuesta de Jeb merece una mención especial, porque realmente va en profundidad y cubre muchos casos extremos.
En particular, señala que una referencia de variable / parámetro mal construida, como %~puede romper cualquiera de las soluciones a continuación, incluidas las REMlíneas .


Comentarios de línea completa : el único estilo directamente compatible:

  • REM(o las variaciones de los casos) es el único comentario oficial , y es la opción más segura ; vea la útil respuesta de Joey .

  • ::es un hack (ampliamente utilizado) , que tiene pros y contras :


Si no desea utilizar:: , tienes estas opciones:

  • O bien : para estar seguro, haga una excepción dentro de los (...)bloques y utilícelos REMallí, o no coloque comentarios dentro del (...) todo.
  • O : memorice las reglas dolorosamente restrictivas para el uso seguro del ::interior(...) , que se resumen en el siguiente fragmento:
@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.
)

Emulación de otros estilos de comentarios : en línea y multilínea:

Tenga en cuenta que ninguno de estos estilos es compatible directamente con el idioma del lote , pero puede emularse .


Comentarios en línea :

* Los fragmentos de código a continuación se utilizan vercomo sustituto de un comando arbitrario, para facilitar la experimentación.
* Para que los SETcomandos funcionen correctamente con comentarios en línea, comillas la name=valueparte; por ejemplo, SET "foo=bar". [1]

En este contexto podemos distinguir dos subtipos:

  • Los comentarios de EOL ([al final de la línea]), que se pueden colocar después de un comando, y se extienden invariablemente hasta el final de la línea (nuevamente, cortesía de la respuesta de jeb ):

    • ver & REM <comment>aprovecha el hecho de que REMes un comando válido y &se puede utilizar para colocar un comando adicional después de uno existente.
    • ver & :: <comment>también funciona, pero en realidad solo se puede usar fuera de los (...)bloques , porque su uso seguro allí es aún más limitado que el uso ::independiente.
  • Comentarios dentro de la línea , que se colocan entre múltiples comandos en una línea o, idealmente, incluso dentro de un comando dado.
    Los comentarios dentro de la línea son la forma más flexible (una sola línea) y , por definición, también se pueden usar como comentarios EOL.

    • ver & REM^. ^<comment^> & verpermite insertar un comentario entre comandos (nuevamente, cortesía de la respuesta de jeb ), pero tenga en cuenta cómo <y >necesita ser ^escapado, porque los siguientes caracteres. no se puede usar como está:< > | (mientras que sin escape &o &&o ||iniciar el siguiente comando).

    • %= <comment> =%, como se detalla en la gran respuesta de dbenham , es la forma más flexible , ya que se puede colocar dentro de un comando (entre los argumentos) .
      Aprovecha la sintaxis de expansión variable de una manera que garantiza que la expresión siempre se expanda a la cadena vacía , siempre que el texto del comentario no contenga %ni:
      Me gusta REM, %= <comment> =%funciona bien tanto en (...)bloques externos como internos , pero es más distintivo visualmente; Los únicos inconvenientes son que es más difícil de escribir, más fácil equivocarse sintácticamente y no es ampliamente conocido, lo que puede dificultar la comprensión del código fuente que utiliza la técnica.


Comentarios de varias líneas (bloque de líneas completas) :

  • La respuesta de James K muestra cómo usar una gotodeclaración y una etiqueta para delimitar un comentario de varias líneas de longitud y contenido arbitrarios (que en su caso usa para almacenar información de uso).

  • La respuesta de Zee muestra cómo usar una "etiqueta nula" para crear un comentario de varias líneas, aunque se debe tener cuidado de terminar con todas las líneas interiores ^.

  • La publicación del blog de Rob van der Woude menciona otra opción algo oscura que le permite finalizar un archivo con un número arbitrario de líneas de comentarios : una apertura (solo hace que se ignore todo lo que viene después , siempre que no contenga un (no ^-escaped) ), es decir, siempre que el bloque no esté cerrado .


[1] Usar SET "foo=bar"para definir variables, es decir, poner comillas dobles alrededor del nombre y =el valor combinado , es necesario en comandos tales como SET "foo=bar" & REM Set foo to bar., para garantizar que lo que sigue al valor de la variable deseada (hasta el siguiente comando, en este caso un solo espacio) no se convierte accidentalmente en parte de él.
(Como comentario aparte: SET foo="bar"no solo no evitaría el problema, sino que haría que las comillas dobles fueran parte del valor ).
Tenga en cuenta que este problema es inherente SETe incluso se aplica al espacio en blanco final accidental que sigue al valor, por lo que es recomendable utilizar siempre el SET "foo=bar"enfoque.

mklement0
fuente
7

Esta página dice que el uso de "::" será más rápido bajo ciertas restricciones. Solo una cosa a tener en cuenta al elegir

mishal153
fuente
2
Esto es cierto, al menos para Win7SP1, ::puede ser 6 veces más rápido queREM
jeb
4

buena pregunta ... He estado buscando esta funcionalidad por mucho tiempo también ...

Después de varias pruebas y trucos, parece que la mejor solución es la más obvia ...

-> la mejor manera que encontré para hacerlo, evitando que falle la integridad del analizador, es reutilizando REM:

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

también puede usar multilínea con el truco "NULL LABEL" ... (no olvide el ^ al final de la línea para la continuidad)

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

James K, lo siento, me equivoqué en una buena parte de lo que dije. La prueba que hice fue la siguiente:

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

Esto cumple con su descripción de alternar pero falla con un ") fue inesperado en este momento". mensaje de error.

Hice algunas pruebas más hoy y descubrí que alternar no es la clave, pero parece que la clave es tener un número par de líneas, no tener dos líneas seguidas que comiencen con dos puntos (: :) y no terminen en dos puntos . Considera lo siguiente:

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

¡Esto funciona!

Pero también considere esto:

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

La regla de tener un número par de comentarios no parece aplicarse cuando termina en un comando.

Desafortunadamente, esto es tan ardiente que no estoy seguro de querer usarlo.

Realmente, la mejor solución, y la más segura que se me ocurre, es si un programa como Notepad ++ leería REM como dos puntos dobles y luego escribiría dos puntos dobles como declaraciones REM cuando se guarda el archivo. Pero no conozco dicho programa y tampoco conozco ningún complemento para Notepad ++ que lo haga.

Darin
fuente
2

Una discusión muy detallada y analítica sobre el tema está disponible en ESTA página

Tiene los códigos de ejemplo y los pros / contras de diferentes opciones.

BiLaL
fuente
1
Debe resumir el contenido de los enlaces proporcionados en las respuestas. De lo contrario, se llama una "respuesta de solo enlace", y es completamente inútil si el enlace desaparece. En este caso, la página a la que apunta es bastante chistosa, ya que
elige
0

Hay varias formas de comentar en un archivo por lotes

1) Usando rem

Esta es la forma oficial. Al parecer, lleva más tiempo ejecutarlo que ::, aunque aparentemente deja de analizarse antes de que se procesen los cuidados. El porcentaje de expansión ocurre antes de rem y ::se identifica, por lo que el uso incorrecto de porcentaje, es decir %~, causará errores si hay porcentajes presentes. Seguro de usar en cualquier lugar en bloques de código.

2) El uso de etiquetas :, ::o :;etc.

Para :: comment, ': comentario' es un nombre de etiqueta no válido porque comienza con un carácter no válido. Sin embargo, está bien usar dos puntos en el medio de una etiqueta. Si un espacio comienza al comienzo de la etiqueta, se elimina se : labelconvierte en :label. Si aparece un espacio o dos puntos en el medio de la etiqueta, el resto del nombre no se interpreta, lo que significa que si hay dos etiquetas :f:ooy :f rr, ambas se interpretarán como :fy solo se saltará a la etiqueta definida más tarde en el archivo. El resto de la etiqueta es efectivamente un comentario. Hay varias alternativas a ::, enumeradas aquí . Nunca puedes gotoo calluna ::fooetiqueta. goto :fooy goto ::foono funcionará

Funcionan bien fuera de los bloques de código pero después de una etiqueta en un bloque de código, inválido o no, tiene que haber una línea de comando válida. :: commentes de hecho otro comando válido. Lo interpreta como un comando y no una etiqueta; El comando tiene prioridad. Cuál es el comando para cd al ::volumen, que funcionará si ha ejecutado subst :: C:\, de lo contrario obtendrá un error de no encontrar el volumen. Es por eso :;que podría decirse que es mejor porque no se puede interpretar de esta manera y, por lo tanto, se interpreta como una etiqueta, que sirve como el comando válido. Esto no es recursivo, es decir, la siguiente etiqueta no necesita un comando después. Por eso vienen en parejas.

Debe proporcionar un comando válido después de la etiqueta, por ejemplo echo something. Una etiqueta en un bloque de código tiene que venir con al menos un comando válido, por lo que las líneas vienen en pares de dos. Obtendrá un )error inesperado si hay un espacio o un paréntesis de cierre en la siguiente línea. Si hay un espacio entre las dos ::líneas, obtendrá un error de sintaxis no válido.

También puede usar el operador de intercalación en el ::comentario de la siguiente manera:

@echo off

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

Pero necesita el seguimiento :;por la razón indicada anteriormente.

@echo off

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

Está bien siempre que haya un número par. Esta es sin duda la mejor manera de comentar, con 4 líneas y :;. Con :;usted no obtiene ningún error que deba suprimirse con 2> nulo subst :: C:\. Puede usar subst :: C:\para que el error de volumen no encontrado desaparezca, pero eso significa que también tendrá que poner C: en el código para evitar que su directorio de trabajo se convierta ::\.

Para comentar al final de una línea puede hacer command &::o command & rem comment, pero todavía tiene que haber un número par, así:

@echo off

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

echo hello

El primero echo hello & :;yestiene un comando válido en la siguiente línea pero el segundo & :;yesno, por lo que necesita uno, es decir, el :;.

3) Usar una variable de entorno no válida

%= comment =%. En un archivo por lotes, las variables de entorno que no están definidas se eliminan del script. Esto hace posible usarlos al final de una línea sin usar &. Es personalizado usar una variable de entorno no válida, es decir, una que contenga un signo igual. No se requieren los iguales adicionales, pero lo hace parecer simétrico. Además, los nombres de variables que comienzan con "=" están reservados para variables dinámicas no documentadas. Esas variables dinámicas nunca terminan con "=", por lo que al usar un "=" al principio y al final del comentario, no hay posibilidad de un choque de nombres. El comentario no puede contener %o :.

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

4) Como un comando, redirigiendo stderr a nul

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

5) Al final de un archivo, todo después de un paréntesis no cerrado es un comentario

@echo off
(
echo hello
)

(this is a comment
this is a comment
this is a comment
Lewis Kelsey
fuente