6

I am trying to use the rem command to place a remark in a command line that contains several commands. Here are some examples to illustrate what I mean:

echo Hello & rem.Comment & echo world!

(echo Hello & rem.Comment) & echo world!

This works perfectly fine, both echo commands in each line are executed as I expect. The . seems to modify the behaviour of the rem command so that it does not treat the remaining line as comment:

Hello 
world!

If I placed a SPACE (or any other delimiter TAB, ,, ;, =) instead of the ., the remaining line and therefore the second echo would be ignored (for the second example a More? prompt appears, because the ) is part of the remark and cmd expects a closing ) because of the ():

Hello 

I found out that beside ., the following characters work as well: :, /, \, [, ] and +.
What else works is escaped delimiters: ^SPACE, ^TAB, ^,, ^; and ^=.

Nevertheless, is there a secure and reliable way to do that?

I would be very glad about a solution that works for both command prompt and batch-files.


According to this external reference, the familiar syntax echo. for returning a blank line fails under certain circumstances, hence using echo( is recommended as this is the only reliable method.

However, for rem, the ( does not work, everything after rem( is not recognised as a command.


Since I am aware of a weird bug of the rem command in Windows XP (reference this external link: rem %~), I am interested in a solution that applies to Windows Vista, Windows 7 or higher.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • 2
    From a program design perspective, why would you want to put an inline comment in the middle of the code instead of at either end? – SomethingDark Jan 14 '16 at 02:34
  • 1
    @SomethingDark - Why not? An inline comment can be useful. – dbenham Jan 14 '16 at 03:37
  • 1
    I usually use comments to explain what the code does. It just seems strange to do that before I'm done writing the line I'm commenting on. – SomethingDark Jan 14 '16 at 03:40
  • 1
    @SomethingDark - But it might be perfectly reasonable if a line consists of concatenated commands, – dbenham Jan 14 '16 at 03:50
  • I striked out the wrong claim concerning the `rem %~` issue because it is _not_ limited to Windows XP; so there was likely _no_ change to `cmd` with respect to the `rem` command... – aschipfl Jan 14 '16 at 16:54

2 Answers2

8

The "weird" REM %~ "bug" is not limited to XP. It is present in all modern versions of Windows that use CMD.EXE. After reading your question, I wrote Simon of SS64 a note to give clarification on the issue. REM can also fail if variable var exists, and you have rem %var:=.

So technically, there is no guaranteed safe way to blindly use REM.

But, if you are willing to accept the fatal % expansion risk, most of your listed hacks are safe to use, but only if the line includes at least one additional command via & or &&.

REM. is never safe to use in any situation if there exists a file named REM (without extension).

The folder dividers \ and / always fail if the current folder contains a file named test.bat and you use REM\..\test.bat.

In a similar fashion, REM:\..\test.bat always fails.

Every one of the other hacks can fail stand-alone in a similar situation. For example, REM^[tab]\..\test.bat fails stand-alone, but works if concatenated with another command. This is the only type of situation I've found where +, [, ], or ^[tab] can fail.

There are additional cases where some of the other hacks can fail.

Any character in the set C (^[space], ^,, ^;, ^=) that are valid in file names can fail stand-alone if remC.bat exists. For example, the following fails stand-alone:

rem^  Fails if "rem .bat" exists

Yet they are all safe when concatenated with another command:

echo OK&rem^  This is safe
rem^  This is safe &echo OK

Temporary Update

Some of the above is wrong. Investigations are ongoing at http://www.dostips.com/forum/viewtopic.php?f=3&t=6895&p=44813#p44813.

I believe the following are the simplest forms that are guaranteed to work in all cases (disregarding invalid % expansion)

REM: At least one space (or other token delimiter) must be after :
REM\ At least one space (or other token delimiter) must be after \
REM/ At least one space (or other token delimiter) must be after /
REM^[tab] At lease one space (or other token delimiter) must be after [tab]

But I won't correct the earlier info until the dust has settled

End Temporary Update



My favorite way to use inline comments is to use impossible variables. Only dynamic pseudo variables can contain = in a name, and no variable name can ever contain two =. So I like to use %= Remark goes here =%. The beauty of this form is it can be used pretty much anywhere with impunity, as long as the comment does not contain % or :. It can even be used safely within parenthesized blocks of code.

for %%F in (*) do (
   %= Comment within code block     =%
   %= 2nd comment within code block =%
   FINDSTR /B %=Must match beginning of line=%  "string" %= Search string =%  "%%F" %= File to search =%
)
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • EDIT - Significant corrections made to failure situations – dbenham Jan 14 '16 at 14:00
  • Thanks! The `%= =%` syntax is really cool but obviously works in batch files only; I am looking for an "all-encompassing" ;-) solution for both `cmd` and batch, so `rem` seems to be the only way... – aschipfl Jan 14 '16 at 16:52
  • @aschipfl - My tests on Win 10 showed potential failure for all variants when used stand-alone (without `&`). But jeb found no failure on Win 7 for some, and I confirmed his finding on my Win 7 at work. I will double check my Win 10 findings when I return home tonight. – dbenham Jan 14 '16 at 19:55
  • I am surprised that `rem^ Comment` works, but I cannot get the into a file name (but I am pretty sure there is a way, and you also mentioned it on [dostips](http://www.dostips.com/forum/viewtopic.php?f=3&t=6895&p=44813#p44813)); anyway, could there be a link to the `/F` option of `cmd` (file/dir. name completion), which is ON as per default? – aschipfl Mar 16 '16 at 23:18
3

This variants of REM seems to be a safe way to enable the & sign in the comment part.

REM/
REM\
REM:

Despite of @dbenham's comment, I can't create any file which would iterfere with these REM variants (I tried REM.bat, REM;.bat and so on).
It's always a good idea to add a space after the REM^<char>.

The problem with %~ can't be solved, as the cmd.exe uses multiple parser phases for each line.
And the %~ error is detected in an early phase (percent expansion phase), just before the phase where a REM would be detected.

But at all, I prefere percent comments for inline comments, described by dbenham

EDIT:
I removed the carets from REM^<char> as it's doesn't matter.

Normally a REM remarks the rest of the line, as the batch parser detects the REM keyword in phase2 of the parser and switches to a specialized parser only for REM.

But when a character is appended to REM the keyword will nt be detected in phase2.
If the character is one of \/;,=+( the parser will remove it later and executes a normal REM command.

That's the cause why the command operators &, &&, |, || can be recognized in this case.

Why rem/ | break fails, but (REM/) | break works?
It's because the pipe starts two seperate cmd child processes.
With surrounding parenthesis the command will be parsed the first time in the child process.
But without parenthesis, the parent process has already parsed the REM/ and checks if the file exists (but doesn't execute it).
But when such a file exists then the parser is smart enough to remove the seperator character and detects that REM is an internal command.
This behaviour looks a bit strange.

jeb
  • 78,592
  • 17
  • 171
  • 225
  • 2
    All hacks are susceptible to the `\..\x.bat` trick. See my revised answer. – dbenham Jan 14 '16 at 14:07
  • Again, you are right, but I simply forgot to mention that you should always add a space behind the `REM^` part. And appending `\..\..\..\windows\system32\calc.exe` seems only to be a problem for `REM^\` and `REM^:` – jeb Jan 14 '16 at 14:11
  • I don't see how adding an additional space avoids `\..\x.bat` issue when REM is used stand-alone. – dbenham Jan 14 '16 at 14:16
  • Your edited answer is effectively what I said in mine, but not nearly so succinctly. I agree that most work with multiple commands. But REM^\ fails stand-alone due to `\..\x.bat` – dbenham Jan 14 '16 at 14:22
  • It's not the same, as I'm still believe that these four REM combinations works always with or without appended `&`. `REM^: \..\x.bat & echo text` and `REM^: \..\x.bat` works both for me. It's expected behaviour, as the filename will stop at the first space/delimiter – jeb Jan 14 '16 at 14:31
  • You must have been testing on the command line. Try it in a bat file ;-) I was surprised that the extra unescaped space did not stop the file name in the batch file. – dbenham Jan 14 '16 at 14:36
  • I've tested it in a batch file all the time !?! I'm testing with Win7x64SP1 and got no problems. What's the difference? Perhaps we should continue this at [Dostips topic](http://www.dostips.com/forum/viewtopic.php?f=3&t=6895) – jeb Jan 14 '16 at 15:04
  • Thanks, very interesting! So the safe variants you listed should work for both command line and batch files? it there a difference if the remark appears last or if it is followed by `&` (or a `)` in case an opening `(` occurs somewhere in front of `rem`)? what about `&&` or `||` by the way? or do all these characters make no difference... – aschipfl Jan 14 '16 at 17:03
  • Why do you `^`-escape the characters? I cannot find any difference to the unescaped variant, except for `rem^=` (which fails when used stand-alone as soon as `rem=.bat` exists; `rem=` ignores any following commands)... – aschipfl Mar 16 '16 at 23:39
  • @aschipfl It seems to avoid problems with appended `\..\x.bat` texts, but dbenham made some more tests at dostips. So it seems, that not all of my variants are bullet proof – jeb Mar 18 '16 at 15:19
  • Besides the `%~` issue, all but the `=`-variant seem to work safely, even without the `^`; in `cmd`, they work even without token separator like _space_ (stand-alone and `&`-combined with other commands); in a batch file and used stand-alone, the token separator is required; in a batch file and `&`-combined with other commands, the token separator seem to be optional; nevertheless, I cannot find a scenario where `^`-escaping or not escaping makes any difference, but perhaps you found one?? – aschipfl Mar 18 '16 at 16:48
  • After some more testing, it seems that the final candidates are `rem/`, `rem\ `and `rem:` (no escaping of the character behind `rem` necessary although it does not harm either) followed by an unescaped token separator (to stop the file path parsing and to avoid trouble with `?` and also `)` if there is no `(` before `rem/`). I personally prefer `rem/` due to readability as the `/` does/should not occur in file paths. – aschipfl Jun 21 '17 at 18:21
  • Anyway, you mentioned in [another post](https://stackoverflow.com/a/19445315) that there is also a `rem` implementation as a "normal" command, so is it possible that `rem` followed by something other than a token separator switches to this "normal" command version, and so this is the reasone why `&`, `&&`, `||`, `(`/`)` and `<`/`>`, `|` are recognised? Could you (or perhaps @dbenham) also explain why `rem/ | break` fails but `(rem/ ) | break` does not? – aschipfl Jun 21 '17 at 18:24
  • 1
    @aschipfl I edited my answer, I hope it's complete now – jeb Jun 22 '17 at 11:06
  • Thanks a lot, jeb! Seems I was on the right track... ;-) – aschipfl Jun 22 '17 at 13:50