Який стиль коментаря я повинен використовувати у пакетних файлах?


284

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

Коментарі в пакетному коді можна робити за допомогою подвійної двокрапки, це краще, ніж використання команди REM, оскільки мітки обробляються перед символами перенаправлення. ::<remark>не викликає проблем, але rem <remark>створює помилки.

Чому тоді більшість посібників та прикладів, які я бачу, використовують REMкоманду? Чи ::працює на всіх версіях Windows?


3
Тільки для запису я бачив проблеми, коли "REM" використовується для коментування рядка з перенаправленням під Windows 98.
Digger

6
Як і в сторону, відповідно до @ коментар для Digger: Пов'язана керівництво для DOS ( command.exe), а НЕ cmd.exe, то NT процесор команд , як знайти на Windows 2000 і далі. rem <remark>в останньому працює добре (оскільки принаймні Windows XP) і REMє офіційним перешкодою та найбезпечнішим вибором в цілому; хоча ::має свої переваги, в кінцевому підсумку проблематичний злом є всередині (…)блоків (про що йдеться у багатьох відповідях тут).
mklement0


1
Отже, яка ситуація з REM точно викликає помилки?
TS

Відповіді:


360

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.


1
@Firedan: Чи відповідає ім'я пакетного файлу та його місцезнаходження (поряд з ім'ям та місцем розташування файлу, на який слід перенаправляти?). Інакше було б непогано спростити приклад.
Joey

15
Приємний дотик, додавши tl; dr
makoshichi

2
Якщо в черзі є затримка використання змінної, :: призведе до деяких повідомлень про помилки, наприклад, Неможливо знайти специфічний драйвер диска ..... Тому краще скористайтеся REM.
Скотт Чу

2
:: коментарі розбираються та спеціальні символи, як> | завершити коментар, і наступний текст не коментується.
mosh

4
@mosh має рацію. Наприклад, %VAR%змінні розширені. Припустимо, у вас є (помилково) set TARGET=C:\Program Files (x86)\"foo.exe", і всередині наявного DO(..)виразу ви :: echo %TARGET%отримаєте помилку, оскільки (x86)розширюється до того, як оцінюється весь вираз, що призводить до невірного DO(..)вираження та дуже незрозумілих помилок (у цьому випадку "\ Microsoft в цей час була несподіваною " ). Вам це навіть не потрібно |або >в вашому вираженні. Однак ::це не справжній коментар REM.
Авель

161

Коментарі з REM

А 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

А для персонажа ;також дозволений один із;,:\/=

РЗМ становить близько 6 разів повільніше , ніж ::(перевірено на Win7SP1 з 100000 рядками коментаря).
Для нормального використання це не важливо (58 мкс проти 360 мкс на рядок коментарів)

Коментарі з ::

::Завжди виконує кінцеву лінію каре.

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

Мітки, а також мітка коментарів :: мають особливу логіку в блоках дужок.
Вони охоплюють завжди два рядки ТАК: команда 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%
)

2
Слід зазначити, що %=коментарі вигадливі з лапками, тобто set foo=bar %=bazпризводять до fooрозширення bar %=baz, як і в той же час set foo="bar" %=baz, тоді як лише в set "foo=bar" %=bazрезультаті fooрозширення за barпризначенням.
LastStar007

3
@ LastStar007: Завжди використовувати стиль цитування set "foo=bar"варто рекомендувати загалом, оскільки це найміцніша форма, яка чітко розмежовує значення. Проблема ви описуєте властива set«s поведінку, а не специфічний для %= … =%коментарів: якщо ви не використовувати "var=val"квотування, setвважає все , що слідує за =значення, в тому числі кінцевих пробілів (до кінця рядка або, якщо це може бути застосовано, почала наступна вбудована команда).
mklement0

28

Інша альтернатива - виразити коментар як змінне розширення, яке завжди розширюється ні до чого.

Імена змінних не можуть містити =, за винятком незадокументованих динамічних змінних, таких як
%=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) коментар не може містити :


ЛОЛ! Зробіть це однією великою змінною! Геніальний! %=ExitCode%? Акуратний. Щодня дізнайтеся щось нове!
Джеймс К

Ви маєте на увазі, що необхідний трейлінг =. Але це, схоже, не буде.
Джеймс К

4
@JamesK - я використовую трейлінг, =щоб щось на зразок% = ExitCode =% - це "коментар", а не динамічна змінна. Я вважаю за краще використовувати стиль, який завжди працює (крім обмежень, зазначених внизу відповіді, звичайно).
dbenham

Дивіться stackoverflow.com/a/20169219/1689714 щодо вивчення динамічних змінних (наприклад,% = ExitCode%% = ExitCodeAscii%% = C:%% = D:%% __ CD __% тощо), що вони означають, як вони встановлюються та ін ..
Кієрон Харді

25

Після того, як я зрозумів, що міг би використовувати ярлик ::для коментарів та коментування, 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
.
.
.

Використовуйте будь-які позначення, які ви хочете *, @і т.д.


Як ви обробляєте /?перемикач, щоб він надрукував це меню?
хоан

1
@hoang setlocal ENABLEDELAYEDEXPANSION <NEWLINE> встановити var =% ~ 1 <NEWLINE> ехо перший парам -% 1 <NEWLINE> АКО! VAR! == "/?" (ГОТИЧНЕ ВИКОРИСТАННЯ) <NEWLINE>: ВИКОРИСТАННЯ <NEWLINE> ехо-бла-бла .. <NEWLINE>
GL2014

16
Чергування однократних та подвійних кольорів повинно бути головним болем, коли ви вставляєте чи видаляєте рядок.

@ GL2014 в основному ви говорите "ви не друкуєте це меню". Ваш приклад код вимагає префіксації відлуння до кожного рядка приміток про використання. Відповідь Джеймса К вводить в оману в тій мірі, в якій це говорить про те, що існує певний спосіб друкувати примітки про використання як написано.
Тімбо

1
@Timbo Я написав підпрограму ( :PrintHelp) для цієї відповіді, яка дійсно робить те, що вимагає @hoang. Я використовую <HELP> і </HELP> як маркери, але ви можете використовувати все, що вам підходить.
cdlvcdlv

21

Ця відповідь намагається зробити прагматичний підсумок безлічі чудових відповідей на цій сторінці:

Чудова відповідь jeb заслуговує на особливу згадку, оскільки вона справді йде вглиб і охоплює багато крайових випадків.
Зокрема, він вказує, що неправильно побудована посилання на змінну / параметр, наприклад, %~може порушити будь-яке рішення нижче - включаючи REMрядки .


Коментарі в цілому рядку - єдиний безпосередньо підтримуваний стиль:

  • REM(або варіанти їх випадків) є єдиною офіційною конструкцією коментарів , і це найбезпечніший вибір - див . корисну відповідь Джоуї .

  • ::це (широко використовується) хак , який має плюси і мінуси :


Якщо ви дійсно хочете використовувати:: , у вас є такий вибір:

  • Або : Для того, щоб убезпечити себе , зробити виняток всередині (...)блоків і використовувати 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 ([до кінця рядка]), які можна розмістити після команди та незмінно поширюватись до кінця рядка (знову ж, люб’язно відповідь на jeb ):

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

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

    • %= <comment> =%, як детально описано у великій відповіді dbenham , є найбільш гнучкою формою , тому що вона може бути розміщена всередині команди (серед аргументів) .
      Він використовує переваги синтаксису змінної розширення таким чином, що вираз завжди розширюється до порожнього рядка - доки текст коментаря не містить %ні:
      Like REM, %= <comment> =%добре працює як зовні, так і всередині (...)блоків, але він більш візуально відрізняється; Єдиний нижній бік полягає в тому, що це важче набрати, легше помилитися синтаксично і не широко відоме, що може перешкоджати розумінню вихідного коду, який використовує методику.


Багаторядкові коментарі :

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

  • Відповідь Zee показує, як використовувати "нульову мітку" для створення багаторядкового коментаря, хоча потрібно обережно припинити всі внутрішні лінії ^.

  • У публікації блогу Роб ван дер Вуде згадується ще один дещо незрозумілий варіант, який дозволяє закінчити файл з довільною кількістю рядків коментарів : Відкриття (лише ігнорує все, що потрапляє після , якщо воно не містить ( ^-сказано) ), тобто, поки блок не закритий .


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


7

На цій сторінці йдеться про те, що використання "::" буде швидше за певних обмежень. Справа, яку слід враховувати при виборі


2
Це правда, принаймні для Win7SP1, ::може бути в 6 разів швидше, ніжREM
16-16

4

гарне запитання ... Я давно шукав цю функціональність ...

після кількох тестів і хитрощів здається, що краще рішення - більш очевидне ...

-> найкращий спосіб, який я знайшов це зробити, запобігаючи невдачі цілісності парсера, - повторне використання 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^ 
)

3

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

@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 ++, які також роблять це.


2

Дуже детальна та аналітична дискусія з цієї теми доступна в ЦЕЙ сторінці

Він містить приклади кодів і плюси / мінуси різних варіантів.


1
Ви повинні узагальнити зміст посилань, наданих у відповідях. В іншому випадку це називається "лише відповідь на посилання", і є абсолютно марним, якщо посилання зникає. У цьому випадку сторінка, на яку вказували, є досить жартівливою, оскільки вона робить свій вибір на основі оптимізації швидкості читання пакетних файлів з повільної дискети :)
GreenAsJade,

0

Існує ряд способів коментування в пакетному файлі

1) Використання рем

Це офіційний шлях. Виконання ::, мабуть, займає більше часу, ніж , хоча, мабуть, припиняє синтаксичний аналіз, перш ніж опрацювати догляд. Відсоток розширення відбувається перед повторним і ::ідентифікується, тому неправильне відсоткове використання, тобто%~ призведе до помилок, якщо відсоток присутній. Безпечно використовувати в будь-якому місці в кодових блоках.

2) Використання міток :, ::або:; т.п.

Бо :: comment": comment" - недійсне ім'я мітки, оскільки воно починається з недійсного символу. Добре використовувати двокрапку в середині етикетки. Якщо простір починається на початку етикетки, він видаляється : labelстає :label. Якщо в середині мітки з’являється пробіл або двокрапка, решта імені не інтерпретується, що означає, що якщо є дві мітки, :f:ooі :f rrобидві будуть інтерпретовані як, :fі до них буде перескановано лише пізніше визначена мітка у файлі. Решта етикетки - це фактично коментар. Є кілька альтернатив ::, перерахованих тут . Ви ніколи не можете gotoабо ярлик. і не вийде.call::foogoto :foogoto ::foo

Вони добре працюють поза кодовими блоками, але після того, як мітка в кодовому блоці, недійсна чи ні, має бути дійсний командний рядок. :: commentце справді ще одна дійсна команда. Він трактує це як команду, а не мітку; команда має перевагу. Яка команда cd до ::тома, яка буде працювати, якщо ви виконали subst :: C:\, інакше ви не можете знайти помилку гучності. Ось чому :;це, мабуть, краще, тому що його не можна інтерпретувати таким чином, і тому він інтерпретується як мітка, яка служить дійсною командою. Це не рекурсивно, тобто наступна мітка після неї не потребує команди. Тому вони приходять у двійки.

Вам потрібно надати дійсну команду після мітки, наприклад echo something. Мітка в кодовому блоці повинна містити щонайменше одну дійсну команду, тому рядки надходять парами по дві. Ви отримаєте несподівану )помилку, якщо в наступному рядку буде пробіл або дужки, що закриваються. Якщо між двома ::рядками є пробіл, ви отримаєте помилкову синтаксичну помилку.

Ви також можете скористатися оператором caret в ::коментарі так:

@echo off

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

Але вам потрібна остання :;з причини, зазначеної вище.

@echo off

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

Це добре, поки є парне число. Це, безсумнівно, найкращий спосіб коментувати - 4 рядки та :;. З :;вами не виникає помилок, які потрібно придушити за допомогою 2> nulабо subst :: C:\. Ви можете використати subst :: C:\для усунення помилки не знайденого обсягу, але це означає, що вам доведеться також вставити C: у код, щоб запобігти становленню вашої робочої каталоги ::\.

Для коментаря в кінці рядка ви можете зробити command &::або command & rem comment, але по- , як і раніше має бути парне число, наприклад , так:

@echo off

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

echo hello

Перший echo hello & :;yesмає дійсну команду в наступному рядку, але другий & :;yes- ні, тому йому потрібна одна, тобто :;.

3) Використання недійсної змінної середовища

%= comment =%. У пакетному файлі змінні середовища, які не визначені, видаляються із сценарію. Це дає можливість використовувати їх у кінці рядка без використання &. Це звичайно використовувати недійсну змінну середовища, тобто таку, яка містить знак рівності. Додаткових рівних не потрібно, але це виглядає симетрично. Також імена змінних, що починаються з "=", зарезервовані для незадокументованих динамічних змінних. Ці динамічні змінні ніколи не закінчуються на "=", тому, використовуючи "=" як на початку, так і в кінці коментаря, немає можливості зіткнення імені. Коментар не може містити %або :.

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

4) Як команда, перенаправляючи stderr на нуль

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

5) В кінці файлу все після незакритих дужок - це коментар

@echo off
(
echo hello
)

(this is a comment
this is a comment
this is a comment
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.