Какой стиль комментариев следует использовать в пакетных файлах?

Я писал несколько пакетных файлов, и я столкнулся с этим руководством пользователя, который был довольно информативным. Одна вещь, которая показала мне, это то, что строки можно прокомментировать не только с помощью REM, но также и с ::. В нем говорится:

Комментарии в пакетном коде могут быть сделаны с использованием двойной двоеточия, это лучше, чем использование команды REM, потому что метки обрабатываются перед символами перенаправления. ::<remark> не вызывает проблем, но rem <remark> создает ошибки.

Почему же большинство руководств и примеров, которые я вижу, используют команду REM? Работает ли :: на всех версиях Windows?

Ответ 1

tl; dr: REM - это документированный и поддерживаемый способ встраивания комментариев в пакетные файлы.


:: - это, по сути, пустая метка, к которой никогда нельзя подпрыгивать, тогда как REM - действительная команда, которая просто ничего не делает. В любом случае (по крайней мере, в Windows 7) наличие операторов перенаправления вызывает проблему.

Тем не менее, ::, как известно, ошибочно работает в блоках при определенных обстоятельствах, анализируется не как метка, а как своего рода буква диска. Я немного расплывчатый, где точно, но этого достаточно, чтобы заставить меня использовать REM исключительно. Это документированный и поддерживаемый способ встраивания комментариев в пакетные файлы, тогда как :: является просто артефактом конкретной реализации.

ИЗМЕНИТЬ

Вот пример, где :: создает проблему в цикле FOR.

Этот пример не будет работать в файле с именем test.bat на рабочем столе:

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

Хотя этот пример будет корректно работать как комментарий:

@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

Проблема заключается в попытке перенаправить вывод в файл. Мое лучшее предположение заключается в том, что он интерпретирует :: как экранированную метку с именем :echo.

Ответ 2

Комментарии с REM

A REM может отметить полную строку, также многострочную каретку на конце строки, если это не конец первого токена.

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, за которым следуют некоторые символы .:\/=, работает немного иначе, он не комментирует амперсанд, поэтому вы можете использовать его как встроенный комментарий.

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

Но чтобы избежать проблем с существующими файлами типа REM, REM.bat или REM;.bat, следует использовать только модифицированный вариант.

REM^;<space>Comment

И для символа ; также разрешен один из ;,:\/=

REM примерно в 6 раз медленнее, чем :: (тестируется на Win7SP1 с 100000 строками комментариев).
Для нормального использования это не важно (58 мкс против 360 мкс за строку комментария)

Комментарии с::

A :: всегда выполняет каретку конца строки.

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

Ярлыки, а также ярлык комментариев :: имеют специальную логику в блоках скобок.
Они охватывают всегда две строки SO: команда goto не работает.
Поэтому они не рекомендуются для блоков скобок, поскольку они часто являются причиной ошибок синтаксиса.

С ECHO ON показана строка REM, но не строка, прокомментированная с помощью ::

Оба не могут прокомментировать остальную часть строки, поэтому простой %~ приведет к синтаксической ошибке.

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

Но REM может остановить парсерный парсер на ранней стадии, даже до того, как будет выполнена специальная фаза.

@echo ON
REM This caret ^ is visible

Вы можете использовать & REM или &:: для добавления комментария в конец командной строки. Этот подход работает, потому что '&' вводит новую команду в одну строку.

Комментарии с процентными знаками% = комментарий =%

Существует стиль комментариев с символами процента.

В действительности это переменные, но они не имеют ничего общего. Но преимущество в том, что их можно разместить в одной строке, даже без &.
Знак равенства гарантирует, что такая переменная не может существовать.

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

Стиль процента рекомендуется для пакетных макросов, так как он не изменяет поведение во время выполнения, поскольку комментарий будет удален при определении макроса.

set $test=(%\n%
%=Start of code=% ^
echo myMacro%\n%
)

Ответ 3

После того, как я понял, что могу использовать ярлык ::, чтобы комментировать и комментировать код REM, выглядел просто уродливым для меня. Как уже упоминалось, двойная двоеточие может вызвать проблемы при использовании внутри () заблокированного кода, но я обнаружил обход, чередуя метки :: и : space

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

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

Это не уродливо, как REM, и фактически добавляет немного стиля в ваш код.

Поэтому вне кодовых блоков я использую ::, а внутри них чередуюсь между :: и :.

Кстати, для больших кусков комментариев, например, в заголовке вашего командного файла, вы можете полностью исключить специальные команды и символы, просто goto используя ваши комментарии. Это позволяет использовать любой метод или стиль разметки, который вы хотите, несмотря на тот факт, что если CMD когда-либо пытался обработать эти строки, он бы выбросил шип.

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

Используйте то, что вы пожелаете *, @ и т.д.

Ответ 4

Другой альтернативой является выражение комментария как расширение переменной, которое всегда расширяется до нуля.

Имена переменных не могут содержать =, за исключением недокументированных динамических переменных, таких как %=ExitCode% и %=C:%. Ни одно имя переменной никогда не может содержать = после 1-й позиции. Поэтому я иногда использую следующее для включения комментариев в скобках в скобках:

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

Это также хороший метод для включения комментариев в строку

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

Ведущий = не нужен, но мне нравится, если для симметрии.

Существуют два ограничения:

1) комментарий не может содержать %

2) комментарий не может содержать :

Ответ 5

Этот ответ пытается получить прагматическое резюме из множества замечательных ответов на этой странице:

jeb great answer заслуживает особого упоминания, потому что он действительно углубляется и охватывает множество случаев краев.
Примечательно, что он указывает, что неверно построенный параметр/параметр, такой как %~, может нарушить любое из нижеприведенных решений - включая строки REM.


Всего строки комментариев - единственный поддерживаемый стиль:

  • REM (или его варианты) является только официальной конструкцией комментариев и является безопасным выбором - см. Полезный ответ Joey.

  • :: - это (широко используемый) хак, который имеет плюсы и минусы:

    • Pros

    • против

      • Внутри блоков (...) :: может нарушить команду, а правила для безопасного использования ограничены и не просто запомнить - см. ниже.

Если вы хотите использовать ::, у вас есть следующие варианты:

  • Либо: чтобы быть в безопасности, сделайте исключение внутри блоков (...) и используйте REM там или не размещайте комментарии внутри (...) вообще.
  • Или: Запомните болезненно ограничительные правила безопасного использования :: внутри (...), которые суммируются в следующем фрагменте:
@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.
)

Эмуляция других стилей комментариев - встроенная и многострочная:

Обратите внимание, что ни один из этих стилей напрямую не поддерживается языковым пакетом, но может быть эмулирован.


Встроенные комментарии:

* В приведенных ниже фрагментах кода используйте ver как резерв для произвольной команды, чтобы облегчить экспериментирование.
* Чтобы команды SET работали корректно с встроенными комментариями, выполните двойную кавычку name=value; например, SET "foo=bar". [1]

В этом контексте мы можем выделить два подтипа:

  • комментарии EOL ([to-the-] end-of-line), которые могут быть размещены после команды и неизменно проходят до конца строки (опять же, любезность jeb answer):

    • ver & REM <comment> использует тот факт, что REM является допустимой командой, а & может использоваться для размещения дополнительной команды после существующей.
    • ver & :: <comment> работает тоже, но на самом деле используется только вне блоков (...), так как его безопасное использование еще более ограничено, чем использование автономного ::.
  • Внутристрочные комментарии, которые могут быть размещены между несколькими командами на линии или идеально даже внутри данной команды.
    Внутрикорректные комментарии являются наиболее гибкой (однострочной) формой и могут по определению также использоваться как комментарии EOL.

    • ver & REM^. ^<comment^> & ver позволяет вставлять комментарий между командами (опять же, любезно предоставлено jeb answer), но обратите внимание, как < и > должны быть ^ -сказаны, потому что следующие символы. не может использоваться как-есть: < > | (тогда как unescaped & или && или || запустит следующую команду).

    • %= <comment> =%, как подробно описано в dbenham отличном ответе, является самой гибкой формой, потому что она может быть помещенным внутри команды (среди аргументов).
      Он использует синтаксис переменной расширения таким образом, чтобы выражение всегда расширялось до пустой строки - , если текст комментария не содержит ни %, ни :
      Как REM, %= <comment> =% хорошо работает как внутри, так и внутри (...), но он более визуально отличается; единственные нижние стороны - это то, что их сложнее вводить, проще получить синтаксически и не широко известно, что может помешать пониманию исходного кода, использующего эту технику.


Комментарии к нескольким строкам (целые строки):

  • Ответ Джеймса К. показывает, как использовать оператор goto и метку, чтобы разграничить многострочный комментарий произвольная длина и содержание (которое в его случае используется для хранения информации об использовании).

  • Ответ Zee показывает, как использовать "нулевую метку" для создания многострочного комментария, хотя уход должен быть для завершения всех внутренних линий с помощью ^.

  • Сообщение в блоге Роб ван дер Вуде упоминает еще один неясный вариант, который позволяет завершать файл произвольным количество строк комментариев: открытие ( приводит только к тому, что происходит после игнорирования, если оно не содержит (^ -escaped) ), т.е. до тех пор, пока блок не закрыт.


[1] Используя SET "foo=bar" для определения переменных - т.е. размещение двойных кавычек вокруг имени и = и комбинированное значение - необходимо в командах, таких как SET "foo=bar" & REM Set foo to bar., чтобы гарантировать, что следует за предполагаемым значением переменной (вплоть до следующей команды, в данном случае одного пробела), случайно не становится ее частью.
(В стороне: SET foo="bar" не только не устранит проблему, она сделает двойные кавычки частью значения).
Обратите внимание, что эта проблема присуща SET и даже применяется к случайным конечным пробелам после значения, поэтому рекомендуется всегда использовать подход SET "foo=bar".

Ответ 6

Эта страница сообщает, что использование "::" будет быстрее при определенных ограничениях Просто подумайте, выбирая

Ответ 7

Хороший вопрос... Я тоже давно искал эту функциональность...

после нескольких тестов и трюков, кажется, лучшее решение является более очевидным...

- > Лучший способ, который я нашел, чтобы предотвратить целостность парсера, повторное использование REM:

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

вы также можете использовать мультилинию с трюком "NULL LABEL"... (не забывайте ^ в конце строки для непрерывности)

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

Ответ 8

Очень подробное и аналитическое обсуждение этой темы доступно на ЭТА страница

У этого есть примеры кодов и плюсы/минусы различных опций.

Ответ 9

Джеймс К, извините, что я ошибся в том, что сказал. Тест, который я сделал, состоял в следующем:

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

Это соответствует вашему описанию чередующихся, но неудачно с ") было неожиданным в это время." сообщение об ошибке.

Сегодня я провел несколько дальнейших испытаний и обнаружил, что чередование не является ключом, но, похоже, ключ имеет четное количество строк, не имеющих двух строк подряд, начиная с двойных двоеточий (::) и не заканчивая в двойных двоеточиях. Рассмотрим следующее:

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

Это работает!

Но также рассмотрим это:

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

Правило наличия четного числа комментариев, похоже, не применяется при завершении команды.

К сожалению, это достаточно просто, что я не уверен, что хочу его использовать.

Действительно, лучшим решением и самым безопасным, о котором я могу думать, является то, что программа, например, Notepad ++, читала бы REM как двойные двоеточия, а затем записывала бы двойные двоеточия в качестве операторов REM при сохранении файла. Но я не знаю о такой программе, и я не знаю никаких плагинов для Notepad ++, которые тоже это делают.