Quale stile di commento dovrei usare nei file batch?


284

Ho scritto alcuni file batch e mi sono imbattuto in questa guida per l'utente , che è stata piuttosto istruttiva. Una cosa che mi ha mostrato è che le righe possono essere commentate non solo con REM, ma anche con ::. Dice:

I commenti nel codice batch possono essere fatti usando un doppio punto, questo è meglio che usare il comando REM perché le etichette vengono elaborate prima dei simboli di reindirizzamento. ::<remark>non causa problemi ma rem <remark>produce errori.

Perché allora, la maggior parte delle guide e degli esempi che vedo usano il REMcomando? Funziona ::su tutte le versioni di Windows?


3
Per la cronaca, ho riscontrato problemi quando "REM" viene utilizzato per commentare una riga con reindirizzamento in Windows 98.
Digger

6
A parte questo, in linea con il commento di @ Digger: la guida collegata è per DOS ( command.exe), non per cmd.exeil processore dei comandi NT come si trova in Windows 2000 in poi. rem <remark>funziona benissimo in quest'ultimo ( almeno da Windows XP), ed REMè l'edificio ufficiale e la scelta più sicura in assoluto; mentre ::ha i suoi vantaggi, è in definitiva un hack problematico all'interno dei (…)blocchi (come discusso in molte risposte qui).
mklement0


1
Quindi, quale situazione con REM causa esattamente errori?
TS,

Risposte:


360

tl; dr: REM è il modo documentato e supportato per incorporare commenti in file batch.


::è essenzialmente un'etichetta vuota a cui non si può mai saltare, mentre REMè un comando effettivo che non fa proprio nulla. In nessuno dei due casi (almeno su Windows 7) la presenza di operatori di reindirizzamento causa un problema.

Tuttavia, ::è noto che si comportano in modo anomalo in blocchi in determinate circostanze, essendo analizzati non come un'etichetta ma come una sorta di lettera di unità. Sono un po 'confuso su dove esattamente ma questo da solo è abbastanza per farmi usare REMesclusivamente. È il modo documentato e supportato per incorporare i commenti nei file batch, mentre ::è semplicemente un artefatto di un'implementazione particolare.


Ecco un esempio in cui ::produce un problema in un FORciclo.

Questo esempio non funzionerà in un file chiamato test.batsul desktop:

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

Mentre questo esempio funzionerà correttamente come commento:

@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

Il problema sembra essere quando si tenta di reindirizzare l'output in un file. La mia ipotesi migliore è che si sta interpretando ::come un'etichetta di escape chiamata :echo.


1
@Firedan: il nome del file batch e la sua posizione sono pertinenti (insieme al nome e alla posizione del file su cui reindirizzare?). Altrimenti sarebbe bello semplificare l'esempio.
Joey,

15
Bel tocco aggiungendo un tl; dr
makoshichi

2
Se c'è un ritardo nell'uso della variabile in linea, :: causerà alcuni messaggi di errore, ad es. Impossibile trovare il driver del disco specifico ..... Quindi meglio usare REM.
Scott Chu,

2
:: i commenti vengono analizzati e caratteri speciali come> | termina il commento e il seguente testo non è commentato.
mosh,

4
@mosh ha ragione. Ad esempio, le %VAR%variabili vengono espanse. Supponiamo di avere (erroneamente) set TARGET=C:\Program Files (x86)\"foo.exe", e all'interno di DO(..)un'espressione che :: echo %TARGET%hai otterrai un errore perché (x86)si espande prima che l'intera espressione venga valutata, portando a DO(..)un'espressione non valida e ad errori molto inspiegabili (in questo caso "\ Microsoft era inattesa al momento " ). Non hai nemmeno bisogno |o >nella tua espressione. A ::non è un vero commento, lo REMè, però.
Abele,

161

Commenti con REM

A REMpuò notare una linea completa, anche un punto di inserimento multilinea alla fine della linea, se non è la fine del primo 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 seguito da alcuni caratteri .:\/=funziona in modo leggermente diverso, non commenta una e commerciale, quindi puoi usarlo come commento incorporato.

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

Ma per evitare problemi con file esistenti come REM, REM.bato REM;.batsolo una variante modificata dovrebbe essere utilizzata.

REM^;<space>Comment

E per il personaggio ;è anche permesso uno dei;,:\/=

REM è circa 6 volte più lento di ::(testato su Win7SP1 con 100000 righe di commento).
Per un uso normale non è importante (58µs contro 360µs per riga di commento)

Commenti con ::

A esegue:: sempre un punto di fine riga.

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

Le etichette e anche l' etichetta dei commenti :: hanno una logica speciale nei blocchi tra parentesi.
Si estendono sempre su due righe SO: il comando goto non funziona .
Pertanto non sono raccomandati per i blocchi tra parentesi, poiché spesso sono la causa di errori di sintassi.

Con ECHO ONuna REMlinea illustrata, ma non una linea commentato con::

Entrambi non possono davvero commentare il resto della riga, quindi un semplice %~causerà un errore di sintassi.

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

Ma REM è in grado di arrestare il parser batch in una fase iniziale, anche prima che venga eseguita la fase carattere speciale.

@echo ON
REM This caret ^ is visible

Puoi usare & REM o & :: per aggiungere un commento alla fine della riga di comando. Questo approccio funziona perché '&' introduce un nuovo comando sulla stessa riga.

Commenti con segni di percentuale% = comment =%

Esiste uno stile di commento con segni di percentuale.

In realtà si tratta di variabili ma si espandono a nulla.
Ma il vantaggio è che possono essere posizionati sulla stessa linea, anche senza &.
Il segno di uguale assicura che tale variabile non può esistere.

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

Lo stile percentuale è consigliato per le macro batch, poiché non modifica il comportamento di runtime, poiché il commento verrà rimosso quando viene definita la macro.

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

2
Va notato che i %=commenti sono pignoli con le virgolette, vale set foo=bar %=baza dire si traduce in fooespansione bar %=baz, così come set foo="bar" %=baz, mentre si set "foo=bar" %=baztraduce solo in fooespansione barcome previsto.
LastStar007,

3
@ LastStar007: vale sempre la set "foo=bar"pena utilizzare sempre lo stile di quotazione , in quanto è la forma più solida che delimita chiaramente il valore. Il problema si sta descrivendo è inerente a set's comportamento, e non specifiche per %= … =%i commenti: a meno di utilizzare "var=val"citando, setconsidera tutto ciò che segue il =valore, tra cui spazi finali (fino alla fine della linea o, se del caso, l'inizio di il prossimo comando incorporato).
mklement0

28

Un'altra alternativa è quella di esprimere il commento come un'espansione variabile che si espande sempre nel nulla.

I nomi delle variabili non possono contenere =, ad eccezione delle variabili dinamiche non documentate come
%=ExitCode%e %=C:%. Nessun nome di variabile può mai contenere un =dopo la prima posizione. Quindi a volte uso quanto segue per includere commenti all'interno di un blocco tra parentesi:

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

È anche un buon metodo per incorporare commenti in linea

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

Il comando =non è necessario, ma mi piace se per la simmetria.

Esistono due restrizioni:

1) il commento non può contenere %

2) il commento non può contenere :


LOL! Rendilo una variabile di grandi dimensioni! Genio! %=ExitCode%? Neat. Impara qualcosa di nuovo ogni giorno!
James K,

Implichi che il trailing =sia necessario. Ma non sembra essere.
James K,

4
@JamesK - Uso il trailing in =modo che qualcosa come% = ExitCode =% sia un "commento" e non una variabile dinamica. Preferisco usare uno stile che funzioni sempre (tranne per le limitazioni annotate in fondo alla risposta ovviamente).
dbenham,

Vedi stackoverflow.com/a/20169219/1689714 per un'esplorazione delle variabili dinamiche (es.% = ExitCode%% = ExitCodeAscii%% = C:%% = D:%% __ CD __% ecc.), Cosa significano, come sono pronti, ecc.
Kieron Hardy

25

Dopo aver capito che potevo usare l'etichetta ::per fare commenti e commentare il codice mi REMsembrava semplicemente brutto. Come è stato detto, il doppio punto può causare problemi quando viene utilizzato all'interno del ()codice bloccato, ma ho scoperto una soluzione alternativa alternando le etichette ::e:space

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

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

Non è brutto REMe in realtà aggiunge un po 'di stile al tuo codice.

Quindi al di fuori dei blocchi di codice che uso ::e al loro interno alterno tra ::e :.

A proposito, per grandi quantità di commenti, come nell'intestazione del tuo file batch, puoi evitare comandi e caratteri speciali completamente semplicemente gotoinserendo i tuoi commenti. Questo ti consente di utilizzare qualsiasi metodo o stile di markup che desideri, nonostante il fatto che se CMDmai effettivamente tentasse di elaborare quelle linee, sarebbe sibilante.

@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 qualunque notazione desideri *, @ecc.


Come gestite l' /?interruttore per farlo stampare questo menu?
Hoang

1
@hoang setlocal ENABLEDELAYEDEXPANSION <NEWLINE> set var =% ~ 1 <NEWLINE> il primo parametro echo è% 1 <NEWLINE> IF! VAR! == "/?" (GOTO USAGE) <NEWLINE>: USAGE <NEWLINE> echo blah blah .. <NEWLINE>
GL2014

16
I due punti alternati singoli e doppi devono essere un mal di testa quando si inserisce o si elimina una riga.

@ GL2014 in pratica stai dicendo " non stampi questo menu". Il codice di esempio richiede l'eco prefissato su ciascuna riga delle note di utilizzo. La risposta di James K è fuorviante nella misura in cui suggerisce che esiste un modo per stampare le note d'uso come scritte.
Timbo,

1
@Timbo Ho scritto una subroutine ( :PrintHelp) per questa risposta che fa davvero quello che @hoang chiede. Uso <HELP> e </HELP> come marcatori ma puoi usare quello che preferisci.
cdlvcdlv,

21

Questa risposta tenta un sommario pragmatico delle molte grandi risposte in questa pagina:

La grande risposta di Jeb merita una menzione speciale, perché è davvero approfondita e copre molti casi limite.
In particolare, sottolinea che un riferimento variabile / parametro errato come quello %~può spezzare una qualsiasi delle soluzioni seguenti, comprese le REMlinee .


Commenti a linea intera - l'unico stile direttamente supportato:

  • REM(o varianti del caso) è l' unico costrutto ufficiale per i commenti ed è la scelta più sicura - vedi la risposta utile di Joey .

  • ::è un hack (ampiamente utilizzato) , che ha pro e contro :

    • Pro :

    • Contro :

      • All'interno dei (...)blocchi, è ::possibile interrompere il comando e le regole per un utilizzo sicuro sono restrittive e non facili da ricordare : vedere di seguito.

Se non volete usare:: , ci sono queste scelte:

  • In entrambi i casi : per sicurezza, fai un'eccezione all'interno dei (...)blocchi e usali REMlì, o non inserire commenti all'interno (...) .
  • Oppure : Memorizzare le regole dolorosamente restrittive per l'uso sicuro di ::dentro(...) , che sono riassunte nella seguente frammento:
@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.
)

Emulazione di altri stili di commento - in linea e multilinea:

Si noti che nessuno di questi stili è direttamente supportato dal linguaggio batch , ma può essere emulato .


Commenti in linea :

* Gli snippet di codice riportati di seguito utilizzano vercome supporto per un comando arbitrario, in modo da facilitare la sperimentazione.
* Per far SETfunzionare correttamente i comandi con i commenti incorporati, citare due volte la name=valueparte; ad es SET "foo=bar". [1]

In questo contesto possiamo distinguere due sottotipi:

  • Commenti EOL ([to-the-] end-of-line), che possono essere inseriti dopo un comando, e invariabilmente si estendono fino alla fine della riga (di nuovo, per gentile concessione della risposta di Jeb ):

    • ver & REM <comment>sfrutta il fatto che REMè un comando valido e &può essere utilizzato per inserire un comando aggiuntivo dopo uno esistente.
    • ver & :: <comment>funziona anche, ma è davvero utilizzabile solo al di fuori dei (...)blocchi , perché il suo uso sicuro è ancora più limitato rispetto all'utilizzo ::autonomo.
  • Commenti all'interno della riga , che possono essere posizionati tra più comandi su una riga o idealmente anche all'interno di un determinato comando.
    I commenti all'interno della riga sono il modulo più flessibile (a riga singola) e possono, per definizione, essere utilizzati anche come commenti EOL.

    • ver & REM^. ^<comment^> & verconsente di inserire un commento tra i comandi (di nuovo, per gentile concessione della risposta di Jeb ), ma nota come <e >necessario essere ^salvati, perché i seguenti caratteri. non può essere usato così com'è:< > | (mentre non è escape &o &&o ||avvia il comando successivo ).

    • %= <comment> =%, come dettagliato nella grande risposta di dbenham , è la forma più flessibile , perché può essere inserita in un comando (tra gli argomenti) .
      Sfrutta la sintassi ad espansione variabile in modo tale che l'espressione si espanda sempre alla stringa vuota - fintanto che il testo del commento non contiene %:
      Like REM , %= <comment> =%funziona bene sia all'esterno che all'interno dei (...)blocchi, ma è visivamente più distintivo; l'unico lato negativo è che è più difficile da scrivere, più facile sbagliare sintatticamente e non ampiamente conosciuto, il che può ostacolare la comprensione del codice sorgente che utilizza la tecnica.


Commenti su più righe (blocco di riga intera) :

  • La risposta di James K mostra come usare gotoun'istruzione e un'etichetta per delimitare un commento multilinea di lunghezza e contenuto arbitrari (che nel suo caso usa per archiviare informazioni sull'uso).

  • La risposta di Zee mostra come usare una "etichetta nulla" per creare un commento su più righe, anche se bisogna fare attenzione a terminare tutte le linee interne ^.

  • Rob van der post del blog di Woude menziona un'altra opzione un po 'oscuro che consente di terminare un file con un numero arbitrario di righe di commento : Un apertura (solo fa sì che tutto ciò che viene dopo di essere ignorato , fintanto che non contiene una (non- ^-escaped) ), ovvero, purché il blocco non sia chiuso .


[1] Usare SET "foo=bar"per definire le variabili - cioè mettere doppie virgolette attorno al nome e =al valore combinato - è necessario in comandi come SET "foo=bar" & REM Set foo to bar., in modo da garantire che ciò che segue il valore della variabile previsto (fino al comando successivo, in questo caso un singolo spazio) non ne diventa accidentalmente parte.
(A parte: SET foo="bar"non solo eviterebbe il problema, renderebbe le doppie virgolette parte del valore ).
Si noti che questo problema è inerente SETe si applica anche agli spazi bianchi finali accidentali che seguono il valore, quindi è consigliabile utilizzare sempre l' SET "foo=bar"approccio.


7

Questa pagina dice che l'uso di "::" sarà più veloce con determinati vincoli Una cosa da considerare quando si sceglie


2
Questo è vero, almeno per Win7SP1, ::può essere 6 volte più veloce diREM
jeb

4

bella domanda ... cerco questa funzionalità anche da molto tempo ...

dopo diversi test e trucchi sembra che la soluzione migliore sia la più ovvia ...

-> il modo migliore che ho trovato per farlo, evitando che l'integrità del parser fallisca, sta riutilizzando REM:

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

puoi anche usare la multilinea con il trucco "NULL LABEL" ... (non dimenticare la ^ alla fine della riga per la continuità)

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

3

James K, mi dispiace di aver sbagliato in una buona parte di quello che ho detto. Il test che ho fatto è stato il seguente:

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

Questo soddisfa la tua descrizione di alternanza ma non riesce con un ") era inaspettato in questo momento." messaggio di errore.

Ho fatto qualche test più lontano oggi e ho scoperto che alternare non è la chiave ma sembra che la chiave stia avendo un numero pari di righe, non avendo due righe consecutive che iniziano con due punti (: :) e non terminano con due punti . Considera quanto segue:

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

Questo funziona!

Ma considera anche questo:

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

La regola di avere un numero pari di commenti non sembra applicarsi quando si termina con un comando.

Sfortunatamente questo è abbastanza scoiattolo che non sono sicuro di volerlo usare.

Davvero, la soluzione migliore, e la più sicura che mi venga in mente, è se un programma come Notepad ++ leggesse REM come doppi punti e poi riscriverebbe doppi punti come istruzioni REM quando il file viene salvato. Ma non sono a conoscenza di un tale programma e non sono a conoscenza di alcun plugin per Notepad ++ che lo faccia neanche.


2

Una discussione molto dettagliata e analitica sull'argomento è disponibile su QUESTA pagina

Ha i codici di esempio e i pro / contro di diverse opzioni.


1
È necessario riepilogare i contenuti dei collegamenti forniti nelle risposte. Altrimenti si chiama "risposta solo collegamento" ed è completamente inutile se il collegamento scompare. In questo caso, la pagina indicata è piuttosto divertente in quanto fa la sua scelta sulla base dell'ottimizzazione della velocità di lettura dei file batch da un floppy disk lento :)
GreenAsJade

0

Esistono diversi modi per commentare in un file batch

1) Utilizzo di rem

Questo è il modo ufficiale. A quanto pare, l'esecuzione richiede più tempo di ::, sebbene apparentemente interrompa l'analisi in anticipo, prima che i caret vengano elaborati. L'espansione percentuale avviene prima di rem e ::viene identificata, quindi un uso percentuale errato, ad esempio %~, causerà errori se sono presenti percentuali. Sicuro da usare ovunque nei blocchi di codice.

2) Utilizzo delle etichette :, ::o :;etc.

Infatti :: comment, ": comment" è un nome di etichetta non valido perché inizia con un carattere non valido. Va bene usare i due punti nel mezzo di un'etichetta però. Se uno spazio inizia all'inizio dell'etichetta, viene rimosso : labeldiventa :label. Se uno spazio o due punti appare nel mezzo dell'etichetta, il resto del nome non viene interpretato nel senso che se ci sono due etichette :f:ooe :f rr, entrambi verranno interpretati come :fe verrà saltato solo l'etichetta definita successivamente nel file. Il resto dell'etichetta è effettivamente un commento. Ci sono più alternative a ::, elencate qui . Non si può mai gotoo di un'etichetta. e non funzionerà.call::foogoto :foogoto ::foo

Funzionano bene al di fuori dei blocchi di codice ma dopo un'etichetta in un blocco di codice, non valida o meno, deve esserci una riga di comando valida. :: commentè davvero un altro comando valido. Lo interpreta come un comando e non come un'etichetta; il comando ha la precedenza. Qual è il comando per cd al ::volume, che funzionerà se lo hai eseguito subst :: C:\, altrimenti otterrai un errore nel trovare il volume. Ecco perché :;è probabilmente migliore perché non può essere interpretato in questo modo, e quindi viene interpretato come un'etichetta, che funge da comando valido. Questo non è ricorsivo, cioè l'etichetta successiva non ha bisogno di un comando dopo di essa. Ecco perché arrivano in due.

È necessario fornire un comando valido dopo l'etichetta, ad es echo something. Un'etichetta in un blocco di codice deve avere almeno un comando valido, quindi le righe si presentano in coppie di due. Verrà visualizzato un )errore imprevisto se nella riga successiva è presente uno spazio o una parentesi di chiusura. Se è presente uno spazio tra le due ::righe, verrà visualizzato un errore di sintassi non valido.

È inoltre possibile utilizzare l'operatore del cursore nel ::commento in questo modo:

@echo off

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

Ma hai bisogno del trailing :;per il motivo sopra indicato.

@echo off

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

Va bene finché c'è un numero pari. Questo è senza dubbio il modo migliore per commentare - con 4 righe e :;. Con :;te non ricevi alcun errore che deve essere eliminato usando 2> nulo subst :: C:\. È possibile utilizzare subst :: C:\per far scomparire l'errore del volume non trovato, ma significa che è necessario inserire anche C: nel codice per evitare che la directory di lavoro diventi ::\.

Per commentare alla fine di una riga puoi fare command &::o command & rem comment, ma deve esserci ancora un numero pari, in questo modo:

@echo off

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

echo hello

Il primo echo hello & :;yesha un comando valido sulla riga successiva ma il secondo & :;yesno, quindi ha bisogno di uno cioè il :;.

3) Utilizzo di una variabile d'ambiente non valida

%= comment =%. In un file batch, le variabili di ambiente non definite vengono rimosse dallo script. Questo rende possibile usarli alla fine di una riga senza usare &. È personalizzato utilizzare una variabile di ambiente non valida, ovvero una contenente un segno di uguale. Gli extra uguali non sono richiesti ma lo rendono simmetrico. Inoltre, i nomi delle variabili che iniziano con "=" sono riservati per variabili dinamiche non documentate. Quelle variabili dinamiche non finiscono mai con "=", quindi usando "=" sia all'inizio che alla fine del commento, non c'è possibilità di scontro tra nomi. Il commento non può contenere %o :.

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

4) Come comando, reindirizzando stderr a nul

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

5) Alla fine di un file, tutto dopo una parentesi non chiusa è un commento

@echo off
(
echo hello
)

(this is a comment
this is a comment
this is a comment
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.