Related
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.
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 =%
)
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.
I have the following command in a windows batch script
echo =%%k-16,INDIRECT.EXT^("'C:\Users\...\Analysis\[ObsStreamflow.xlsx]Sheet1'^!A%%k"^),INDIRECT.EXT^("'C:\Users\...\Analysis\[sim%%j.xlsx]Sheet1'^!B!val!"^),^=C%%k/1000,^=D%%k-B%%k,^=ABS^(E%%k^),^=(E%%k^)^^2,=^(B%%k-B10^),=Sqrt^(B%%k^),=SQRT^(D%%k^),=^(J%%k - B13^)^^2 >>t%%j.csv
where the omitted file path is 38 characters long (I don't think I'm hitting the line limits, but just in case this is the problem). This is a single line in my .bat file, shown here as multiple lines just to make things more readable.
The output is mostly correct, except that where I have ^^2, it just becomes 2 (so I have =(E1)2 and =(J1-B13)2. If I omit the Indirect.Ext text, and just have
echo =%%k-16,a1,b1,^=C%%k/1000,^=D%%k-B%%k,^=ABS^(E%%k^),^=(E%%k^)^^2,=^(B%%k-B10^),=Sqrt^(B%%k^),=SQRT^(D%%k^),=^(J%%k - B13^)^^2 >>t%%j.csv
it prints correctly, so the relevant comments show as =(E1)^2 and =(J1-B13)^2, which is what I am after.
I've not had any luck finding an answer, everything I have found just points to using ^^ to get echo to return ^. I cannot break this command into multiple lines, I need it to be a single row in csv format.
Any suggestions for a fix much appreciated, I only really need to use this for a week or so, don't need an elegant solution, just one that works. - I'm very new to bat scripts (and indeed programming in general), will keep trying different ideas in the mean time.
It's only the exclamation mark that creates the problems for you.
If at least one ! is in your line (and delayed expansion is enabled), then a second caret escape phase will be started.
In this phase quotes aren't regarded, only carets.
A small test
setlocal EnableDelayedExpansion
echo one^1
echo two^^2
echo two^^2 With exclam!
echo five^^^^^& With exclam!
Output
one1
two^2
two2 With exclam
four^& With exclam
So in your sample, you need five carets.
Four to create one caret and the last one to escape the ), as the escape of the special character is only once required.
Not sure what your specific problem is but you can use a trick in Windows to emulate echo -n (echo without a newline).
The commands:
<nul: >file.csv set /p junk=first field
<nul: >>file.csv set /p junk=,second field
>>file.csv echo ,third field
will result in a single line:
first field,second field,third field
That may make it easier for you to avoid the specific problem and, as a bonus, clean up your script so it's a little more readable (such as one field per script line).
It works because set /p var=prompt is the input command. It first outputs prompt without a newline then waits for the user to enter something, assigning it to the var environment variable.
By getting input from nul:, you basically give it an empty string so it doesn't wait. The prompt is output to file.csv without the newline.
In any case, for something this complex, I'd be bypassing cmd.exe for something a little more powerful such as the UNIX text processing tools under CygWin or MinGW (which require installation but are well worth it), or even VBScript scripts (which should be on Windows by default), where you can more easily control the output.
I've been writing some batch files, and I ran into this user guide, which has been quite informative. One thing it showed me was that lines can be commented not just with REM, but also with ::. It says:
Comments in batch code can be made by using a double-colon, this is better than using the REM command because labels are processed before redirection symbols. ::<remark> causes no problems but rem <remark> produces errors.
Why then, do most guides and examples I see use the REM command? Does :: work on all versions of Windows?
tl;dr: REM is the documented and supported way to embed comments in batch files.
:: is essentially a blank label that can never be jumped to, whereas REM is an actual command that just does nothing. In neither case (at least on Windows 7) does the presence of redirection operators cause a problem.
However, :: is known to misbehave in blocks under certain circumstances, being parsed not as a label but as some sort of drive letter. I'm a little fuzzy on where exactly but that alone is enough to make me use REM exclusively. It's the documented and supported way to embed comments in batch files whereas :: is merely an artifact of a particular implementation.
Here is an example where :: produces a problem in a FOR loop.
This example will not work in a file called test.bat on your 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
While this example will work as a comment correctly:
#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
The problem appears to be when trying to redirect output into a file. My best guess is that it is interpreting :: as an escaped label called :echo.
Comments with REM
A REM can remark a complete line, also a multiline caret at the line end, if it's not the end of the first 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 followed by some characters .:\/= works a bit different, it doesn't comment an ampersand, so you can use it as inline comment.
echo First & REM. This is a comment & echo second
But to avoid problems with existing files like REM, REM.bat or REM;.bat only a modified variant should be used.
REM^;<space>Comment
And for the character ; is also allowed one of ;,:\/=
REM is about 6 times slower than :: (tested on Win7SP1 with 100000 comment lines).
For a normal usage it's not important (58µs versus 360µs per comment line)
Comments with ::
A :: always executes a line end caret.
:: This is also a comment^
echo This line is also a comment
Labels and also the comment label :: have a special logic in parenthesis blocks.
They span always two lines SO: goto command not working.
So they are not recommended for parenthesis blocks, as they are often the cause for syntax errors.
With ECHO ON a REM line is shown, but not a line commented with ::
Both can't really comment out the rest of the line, so a simple %~ will cause a syntax error.
REM This comment will result in an error %~ ...
But REM is able to stop the batch parser at an early phase, even before the special character phase is done.
#echo ON
REM This caret ^ is visible
You can use &REM or &:: to add a comment to the end of command line.
This approach works because '&' introduces a new command on the same line.
Comments with percent signs %= comment =%
There exists a comment style with percent signs.
In reality these are variables but they are expanded to nothing.
But the advantage is that they can be placed in the same line, even without &.
The equal sign ensures, that such a variable can't exists.
echo Mytest
set "var=3" %= This is a comment in the same line=%
The percent style is recommended for batch macros, as it doesn't change the runtime behaviour, as the comment will be removed when the macro is defined.
set $test=(%\n%
%=Start of code=% ^
echo myMacro%\n%
)
Performance REM vs :: vs %= =%
In short:
:: and %= =% seems to have the same performance
REM takes ~ 50% more time than ::
In blocks, especially loops only REM consumes time, but :: is removed from the cached block when the block is parsed, therefore it consumes no time
For more info see SO: Question about Comments in Batch *.bat files and speed
This answer attempts a pragmatic summary of the many great answers on this page:
jeb's great answer deserves special mention, because it really goes in-depth and covers many edge cases.
Notably, he points out that a misconstructed variable/parameter reference such as %~ can break any of the solutions below - including REM lines.
Whole-line comments - the only directly supported style:
REM (or case variations thereof) is the only official comment construct, and is the safest choice - see Joey's helpful answer.
:: is a (widely used) hack, which has pros and cons:
Pros:
Visual distinctiveness and, possibly, ease of typing.
Speed, although that will probably rarely matter - see jeb's great answer and Rob van der Woude's excellent blog post.
Cons:
Inside (...) blocks, :: can break the command, and the rules for safe use are restrictive and not easy to remember - see below.
If you do want to use ::, you have these choices:
Either: To be safe, make an exception inside (...) blocks and use REM there, or do not place comments inside (...) altogether.
Or: Memorize the painfully restrictive rules for safe use of :: inside (...), which are summarized in the following snippet:
#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.
)
Emulation of other comment styles - inline and multi-line:
Note that none of these styles are directly supported by the batch language, but can be emulated.
Inline comments:
* The code snippets below use ver as a stand-in for an arbitrary command, so as to facilitate experimentation.
* To make SET commands work correctly with inline comments, double-quote the name=value part; e.g., SET "foo=bar".[1]
In this context we can distinguish two subtypes:
EOL comments ([to-the-]end-of-line), which can be placed after a command, and invariably extend to the end of the line (again, courtesy of jeb's answer):
ver & REM <comment> takes advantage of the fact that REM is a valid command and & can be used to place an additional command after an existing one.
ver & :: <comment> works too, but is really only usable outside of (...) blocks, because its safe use there is even more limited than using :: standalone.
Intra-line comments, which be placed between multiple commands on a line or ideally even inside of a given command.
Intra-line comments are the most flexible (single-line) form and can by definition also be used as EOL comments.
ver & REM^. ^<comment^> & ver allows inserting a comment between commands (again, courtesy of jeb's answer), but note how < and > needed to be ^-escaped, because the following chars. cannot be used as-is: < > | (whereas unescaped & or && or || start the next command).
%= <comment> =%, as detailed in dbenham's great answer, is the most flexible form, because it can be placed inside a command (among the arguments).
It takes advantage of variable-expansion syntax in a way that ensures that the expression always expands to the empty string - as long as the comment text contains neither % nor :
Like REM, %= <comment> =% works well both outside and inside (...) blocks, but it is more visually distinctive; the only down-sides are that it is harder to type, easier to get wrong syntactically, and not widely known, which can hinder understanding of source code that uses the technique.
Multi-line (whole-line block) comments:
James K's answer shows how to use a goto statement and a label to delimit a multi-line comment of arbitrary length and content (which in his case he uses to store usage information).
Zee's answer shows how to use a "null label" to create a multi-line comment, although care must be taken to terminate all interior lines with ^.
Rob van der Woude's blog post mentions another somewhat obscure option that allows you to end a file with an arbitrary number of comment lines: An opening ( only causes everything that comes after to be ignored, as long as it doesn't contain a ( non-^-escaped) ), i.e., as long as the block is not closed.
[1] Using SET "foo=bar" to define variables - i.e., putting double quotes around the name and = and the value combined - is necessary in commands such as SET "foo=bar" & REM Set foo to bar., so as to ensure that what follows the intended variable value (up to the next command, in this case a single space) doesn't accidentally become part of it.
(As an aside: SET foo="bar" would not only not avoid the problem, it would make the double quotes part of the value).
Note that this problem is inherent to SET and even applies to accidental trailing whitespace following the value, so it is advisable to always use the SET "foo=bar" approach.
Another alternative is to express the comment as a variable expansion that always expands to nothing.
Variable names cannot contain =, except for undocumented dynamic variables like
%=ExitCode% and %=C:%. No variable name can ever contain an = after the 1st position. So I sometimes use the following to include comments within a parenthesized block:
::This comment hack is not always safe within parentheses.
(
%= This comment hack is always safe, even within parentheses =%
)
It is also a good method for incorporating in-line comments
dir junk >nul 2>&1 && %= If found =% echo found || %= else =% echo not found
The leading = is not necessary, but I like if for the symmetry.
There are two restrictions:
1) the comment cannot contain %
2) the comment cannot contain :
After I realized that I could use label :: to make comments and comment out code REM just looked plain ugly to me. As has been mentioned the double-colon can cause problems when used inside () blocked code, but I've discovered a work-around by alternating between the labels :: and :space
:: This, of course, does
:: not cause errors.
(
:: But
: neither
:: does
: this.
)
It's not ugly like REM, and actually adds a little style to your code.
So outside of code blocks I use :: and inside them I alternate between :: and :.
By the way, for large hunks of comments, like in the header of your batch file, you can avoid special commands and characters completely by simply gotoing over your comments. This let's you use any method or style of markup you want, despite that fact that if CMD ever actually tried to processes those lines it'd throw a hissy.
#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
.
.
.
Use what ever notation you wish *'s, #'s etc.
This page tell that using "::" will be faster under certain constraints
Just a thing to consider when choosing
good question... I've been looking for this functionality for long too...
after several tests and tricks it seem the better solution is the more obvious one...
--> best way I found to do it, preventing parser integrity fail, is reusing REM:
echo this will show until the next REM &REM this will not show
you can also use multiline with the "NULL LABEL" trick...
(dont forget the ^ at the end of the line for continuity)
::(^
this is a multiline^
comment... inside a null label!^
dont forget the ^caret at the end-of-line^
to assure continuity of text^
)
James K, I'm sorry I was wrong in a fair portion of what I said. The test I did was the following:
#ECHO OFF
(
:: But
: neither
:: does
: this
:: also.
)
This meets your description of alternating but fails with a ") was unexpected at this time." error message.
I did some farther testing today and found that alternating isn't the key but it appears the key is having an even number of lines, not having any two lines in a row starting with double colons (::) and not ending in double colons. Consider the following:
#ECHO OFF
(
: But
: neither
: does
: this
: cause
: problems.
)
This works!
But also consider this:
#ECHO OFF
(
: Test1
: Test2
: Test3
: Test4
: Test5
ECHO.
)
The rule of having an even number of comments doesn't seems to apply when ending in a command.
Unfortunately this is just squirrelly enough that I'm not sure I want to use it.
Really, the best solution, and the safest that I can think of, is if a program like Notepad++ would read REM as double colons and then would write double colons back as REM statements when the file is saved. But I'm not aware of such a program and I'm not aware of any plugins for Notepad++ that does that either.
A very detailed and analytic discussion on the topic is available on THIS page
It has the example codes and the pros/cons of different options.
There are a number of ways to comment in a batch file
1)Using rem
This is the official way. It apparently takes longer to execute than ::, although it apparently stops parsing early, before the carets are processed. Percent expansion happens before rem and :: are identified, so incorrect percent usage i.e. %~ will cause errors if percents are present. Safe to use anywhere in code blocks.
2)Using labels :, :: or :; etc.
For :: comment, ': comment' is an invalid label name because it begins with an invalid character. It is okay to use a colon in the middle of a label though. If a space begins at the start of label, it is removed : label becomes :label. If a space or a colon appears in the middle of the label, the rest of the name is not interpreted meaning that if there are two labels :f:oo and :f rr, both will be interpreted as :f and only the later defined label in the file will be jumped to. The rest of the label is effectively a comment. There are multiple alternatives to ::, listed here. You can never goto or call a ::foo label. goto :foo and goto ::foo will not work.
They work fine outside of code blocks but after a label in a code block, invalid or not, there has to be a valid command line. :: comment is indeed another valid command. It interprets it as a command and not a label; the command has precedence. Which is the command to cd to the :: volume, which will work if you have executed subst :: C:\, otherwise you get a cannot find the volume error. That's why :; is arguably better because it cannot be interpreted in this way, and therefore is interpreted as a label instead, which serves as the valid command. This is not recursive, i.e, the next label does not need a command after it. That's why they come in twos.
You need to provide a valid command after the label e.g. echo something. A label in a code block has to come with at least one valid command, so the lines come in pairs of two. You will get an unexpected ) error if there is a space or a closing parenthesis on the next line. If there is a space between the two :: lines you will get an invalid syntax error.
You can also use the caret operator in the :: comment like so:
#echo off
echo hello
(
:;(^
this^
is^
a^
comment^
)
:;
)
:;^
this^
is^
a^
comment
:;
)
But you need the trailing :; for the reason stated above.
#echo off
(
echo hello
:;
:; comment
:; comment
:;
)
echo hello
It is fine as long as there is an even number. This is undoubtedly the best way to comment -- with 4 lines and :;. With :; you don't get any errors that need to be suppressed using 2> nul or subst :: C:\. You could use subst :: C:\ to make the volume not found error go away but it means you will have to also put C: in the code to prevent your working directory from becoming ::\.
To comment at the end of a line you can do
command &:: or command & rem comment, but there still has to be an even number, like so:
#echo off
(
echo hello & :;yes
echo hello & :;yes
:;
)
echo hello
The first echo hello & :;yes has a valid command on the next line but the second & :;yes does not, so it needs one i.e. the :;.
3)Using an invalid environment variable
%= comment =%. In a batch file, environment variables that are not defined are removed from the script. This makes it possible to use them at the end of a line without using &. It is custom to use an invalid environment variable i.e. one that contains an equals sign. The extra equals is not required but makes it look symmetrical. Also, variable names starting with "=" are reserved for undocumented dynamic variables. Those dynamic variables never end with "=", so by using an "=" at both the start and end of the comment, there is no possibility of a name clash. The comment cannot contain % or :.
#echo off
echo This is an example of an %= Inline Comment =% in the middle of a line.
4)As a command, redirecting stderr to nul
#echo off
(
echo hello
;this is a comment 2> nul
;this is another comment 2> nul
)
5)At the end of a file, everything after an unclosed parenthesis is a comment
#echo off
(
echo hello
)
(this is a comment
this is a comment
this is a comment
This question already has answers here:
How can I echo a newline in a batch file?
(24 answers)
Closed 7 years ago.
Is it possible to put a new line character in an echo line in a batch file?
Basically I want to be able to do the equivalent of:
echo Hello\nWorld
You can do this easily enough in Linux, but I can't work out how to do it in Windows.
echo. prints an empty line.
Example:
echo Hello
echo.
echo world
prints
Hello
world
It can be solved with a single echo.
You need a newline character \n for this.
There are multiple ways to get a new line into the echo
1) This sample use the multiline caret to add a newline into the command,
the empty line is required
echo Hello^
world
2) The next solution creates first a variable which contains one single line feed character.
set \n=^
rem ** Two empty lines are required
Or create the new line with a slightly modified version
(set \n=^
%=DONT REMOVE THIS=%
)
And use this character with delayed expansion
setlocal EnableDelayedExpansion
echo Hello!\n!world
To use a line feed character with the percent expansion you need to create a more complex sequence
echo Hello^%\n%%\n%world
Or you can use the New line hack
REM Creating a Newline variable (the two blank lines are required!)
set \n=^
set NL=^^^%\n%%\n%^%\n%%\n%
REM Example Usage:
echo There should be a newline%NL%inserted here.
But only the delayed expansion of the newline works reliable, also inside of quotes.
After a little experimentation I discovered that it is possible to do it without issuing two separate echo commands as described in How can you echo a newline in batch files?. However to make it work you will need a text editor that does not translate CR to CR+LF.
Type:
#echo First Line
then with NumLock on, hold down the ALT key and type 10 on the numeric keypad before releasing ALT (you must use the numeric keypad, not the top-row number keys). This will insert a CR character. Then type the second line. Depending on your editor and how it handles CR compared with CR+LF you may get:
#echo First Line◙Second Line
or
#echo First Line
Second Line
This works from the command line and will work in a batch file so long as the text editor does not translate CR to CR+LF (which Windows/DOS editors do unless you configure them not to). If the CR is converted to CR+LF, or if you use just LF, the second line is interpreted as a new command.
However, I cannot see why this would be preferable over simply:
#echo First Line
#echo Second Line
Ahaha,
I think I've worked out something close enough...
echo hello&echo.&echo world
Produces:
hello
world
echo.
or
echo(
will do the blank new line. Hope this is helpful.
I found this very informative, so wanted to post a better example using the answers provided
This provides a nicely formatted usage message
if "%1" == """" goto usage
:usage
echo USAGE: %0 [Set properties using -D flag] [Ant Task to Run] &
echo. &
echo Availble Command line properties &
echo -------------------------------- &
...
I think it is not possible. You could only try an ascii-character to this:
http://www.asciitable.com/
But this will perhaps crash your batch-file.
How can you you insert a newline from your batch file output?
I want to do something like:
echo hello\nworld
Which would output:
hello
world
Use:
echo hello
echo:
echo world
echo hello & echo.world
This means you could define & echo. as a constant for a newline \n.
Here you go, create a .bat file with the following in it :
#echo off
REM Creating a Newline variable (the two blank lines are required!)
set NLM=^
set NL=^^^%NLM%%NLM%^%NLM%%NLM%
REM Example Usage:
echo There should be a newline%NL%inserted here.
echo.
pause
You should see output like the following:
There should be a newline
inserted here.
Press any key to continue . . .
You only need the code between the REM statements, obviously.
There is a standard feature echo: in cmd/bat-files to write blank line, which emulates a new line in your cmd-output:
#echo off
echo line1
echo:
echo line2
or
#echo line1 & echo: & echo line2
Output of cited above cmd-file:
line1
line2
Like the answer of Ken, but with the use of the delayed expansion.
setlocal EnableDelayedExpansion
(set \n=^
%=Do not remove this line=%
)
echo Line1!\n!Line2
echo Works also with quotes "!\n!line2"
First a single linefeed character is created and assigned to the \n-variable.
This works as the caret at the line end tries to escape the next character, but if this is a Linefeed it is ignored and the next character is read and escaped (even if this is also a linefeed).
Then you need a third linefeed to end the current instruction, else the third line would be appended to the LF-variable.
Even batch files have line endings with CR/LF only the LF are important, as the CR's are removed in this phase of the parser.
The advantage of using the delayed expansion is, that there is no special character handling at all.
echo Line1%LF%Line2 would fail, as the parser stops parsing at single linefeeds.
More explanations are at
SO:Long commands split over multiple lines in Vista/DOS batch (.bat) file
SO:How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Edit: Avoid echo.
This doesn't answer the question, as the question was about single echo that can output multiple lines.
But despite the other answers who suggests the use of echo. to create a new line, it should be noted that echo. is the worst, as it's very slow and it can completly fail, as cmd.exe searches for a file named ECHO and try to start it.
For printing just an empty line, you could use one of
echo,
echo;
echo(
echo/
echo+
echo=
But the use of echo., echo\ or echo: should be avoided, as they can be really slow, depending of the location where the script will be executed, like a network drive.
echo. Enough said.
If you need it in a single line, use the &. For example,
echo Line 1 & echo. & echo line 3
would output as:
Line 1
line 3
Now, say you want something a bit fancier, ...
set n=^&echo.
echo hello %n% world
Outputs
hello
world
Then just throw in a %n% whenever you want a new line in an echo statement. This is more close to your \n used in various languages.
Breakdown
set n= sets the variable n equal to:
^ Nulls out the next symbol to follow:
& Means to do another command on the same line. We don't care about errorlevel(its an echo statement for crying out loud), so no && is needed.
echo. Continues the echo statement.
All of this works because you can actually create variables that are code, and use them inside of other commands. It is sort of like a ghetto function, since batch is not exactly the most advanced of shell scripting languages. This only works because batch's poor usage of variables, not designating between ints, chars, floats, strings, etc naturally.
If you are crafty, you could get this to work with other things. For example, using it to echo a tab
set t=^&echo. ::there are spaces up to the double colon
When echoing something to redirect to a file, multiple echo commands will not work. I think maybe the ">>" redirector is a good choice:
echo hello > temp
echo world >> temp
If you need to put results to a file, you can use:
(echo a & echo: & echo b) > file_containing_multiple_lines.txt
Just like Grimtron suggests - here is a quick example to define it:
#echo off
set newline=^& echo.
echo hello %newline%world
Output
C:\>test.bat
hello
world
You can also do like this,
(for %i in (a b "c d") do #echo %~i)
The output will be,
a
b
c d
Note that when this is put in a batch file, '%' shall be doubled.
(for %%i in (a b "c d") do #echo %%~i)
If anybody comes here because they are looking to echo a blank line from a MINGW make makefile, I used
#cmd /c echo.
simply using echo. causes the dreaded process_begin: CreateProcess(NULL, echo., ...) failed. error message.
I hope this helps at least one other person out there :)
Ken and Jeb solutions works well.
But the new lines are generated with only an LF character and I need CRLF characters (Windows version).
To this, at the end of the script, I have converted LF to CRLF.
Example:
TYPE file.txt | FIND "" /V > file_win.txt
del file.txt
rename file_win.txt file.txt
If one needs to use famous \n in string literals that can be passed to a variable, may write a code like in the Hello.bat script below:
#echo off
set input=%1
if defined input (
set answer=Hi!\nWhy did you call me a %input%?
) else (
set answer=Hi!\nHow are you?\nWe are friends, you know?\nYou can call me by name.
)
setlocal enableDelayedExpansion
set newline=^
rem Two empty lines above are essential
echo %answer:\n=!newline!%
This way multiline output may by prepared in one place, even in other scritpt or external file, and printed in another.
The line break is held in newline variable. Its value must be substituted after the echo line is expanded so I use setlocal enableDelayedExpansion to enable exclamation signs which expand variables on execution. And the execution substitutes \n with newline contents (look for syntax at help set). We could of course use !newline! while setting the answer but \n is more convenient. It may be passed from outside (try Hello R2\nD2), where nobody knows the name of variable holding the line break (Yes, Hello C3!newline!P0 works the same way).
Above example may be refined to a subroutine or standalone batch, used like call:mlecho Hi\nI'm your comuter:
:mlecho
setlocal enableDelayedExpansion
set text=%*
set nl=^
echo %text:\n=!nl!%
goto:eof
Please note, that additional backslash won't prevent the script from parsing \n substring.
After a sleepless night and after reading all answers herein, after reading a lot of SS64 > CMD and after a lot of try & error I found:
The (almost) Ultimate Solution
TL;DR
... for early adopters.
Important!
Use a text editor for C&P that supports Unicode, e.g. Notepad++!
Set Newline Environment Variable ...
... in the Current CMD Session
Important!
Do not edit anything between '=' and '^'! (There's a character in between though you don't see it. Neither here nor in edit mode. C&P works here.)
:: Sets newline variables in the current CMD session
set \n=^&echo:
set nl=^&echo:
... for the Current User
Important!
Do not edit anything between (the second) '␣' and '^'! (There's a character in between though you don't see it. Neither here nor in edit mode. C&P works here.)
:: Sets newline variables for the current user [HKEY_CURRENT_USER\Environment]
setx \n ^&echo:
setx nl ^&echo:
... for the Local Machine
Important!
Do not edit anything between (the second) '␣' and '^'! (There's a character in between though you don't see it. Neither here nor in edit mode. C&P works here.)
:: Sets newline variables for the local machine [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment]
setx \n ^&echo: /m
setx nl ^&echo: /m
Why just almost?
It does not work with double-quotes that are not paired (opened and closed) in the same printed line, except if the only unpaired double-quote is the last character of the text, e.g.:
works: ""echo %\n%...after "newline". Before "newline"...%\n%...after "newline" (paired in each printed line)
works: echo %\n%...after newline. Before newline...%\n%...after newline" (the only unpaired double-quote is the last character)
doesn't work: echo "%\n%...after newline. Before newline...%\n%...after newline" (double-quotes are not paired in the same printed line)
Workaround for completely double-quoted texts (inspired by Windows batch: echo without new line):
set BEGIN_QUOTE=echo ^| set /p !="""
...
%BEGIN_QUOTE%
echo %\n%...after newline. Before newline...%\n%...after newline"
It works with completely single-quoted texts like:
echo '%\n%...after newline. Before newline...%\n%...after newline'
Added value: Escape Character
Note
There's a character after the '=' but you don't see it here but in edit mode. C&P works here.
:: Escape character - useful for color codes when 'echo'ing
:: See https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#text-formatting
set ESC=
For the colors see also https://imgur.com/a/EuNXEar and https://gist.github.com/gerib/f2562474e7ca0d3cda600366ee4b8a45.
2nd added value: Getting Unicode characters easily
A great page for getting 87,461 Unicode characters (AToW) by keyword(s): https://www.amp-what.com/.
The Reasons
The version in Ken's answer works apparently (I didn't try it), but is somehow...well...you see:
set NLM=^
set NL=^^^%NLM%%NLM%^%NLM%%NLM%
The version derived from user2605194's and user287293's answer (without anything between '=' and '^'):
set nl=^&echo:
set \n=^&echo:
works partly but fails with the variable at the beginning of the line to be echoed:
> echo %\n%Hello%\n%World!
echo & echo:Hello & echo:World!
echo is ON.
Hello
World
due to the blank argument to the first echo.
All others are more or less invoking three echos explicitely.
I like short one-liners.
The Story Behind
To prevent set \n=^&echo: suggested in answers herein echoing blank (and such printing its status) I first remembered the Alt+255 user from the times when Novell was a widely used network and code pages like 437 and 850 were used. But 0d255/0xFF is ›Ÿ‹ (Latin Small Letter Y with diaeresis) in Unicode nowadays.
Then I remembered that there are more spaces in Unicode than the ordinary 0d32/0x20 but all of them are considered whitespaces and lead to the same behaviour as ›␣‹.
But there are even more: the zero width spaces and joiners which are not considered as whitespaces. The problem with them is, that you cannot C&P them since with their zero width there's nothing to select. So, I copied one that is close to one of them, the hair space (U+200A) which is right before the zero width space (U+200B) into Notepad++, opened its Hex-Editor plugin, found its bit representation E2 80 8A and changed it to E2 80 8B. Success! I had a non-whitespace character that's not visible in my \n environment variable.
To start a new line in batch, all you have to do is add "echo[", like so:
echo Hi!
echo[
echo Hello!
why not use substring/replace space to echo;?
set "_line=hello world"
echo\%_line: =&echo;%
Results:
hello
world
Or, replace \n to echo;
set "_line=hello\nworld"
echo\%_line:\n=&echo;%
For windows 10 with virtual terminal sequences there exists the means control the cursor position to a high degree.
To define the escape sequence 0x1b, the following can be used:
#Echo off
For /f %%a in ('echo prompt $E^| cmd')Do set \E=%%a
To output a single newline Between Strings:
<nul set /p "=Hello%\E%[EWorld"
To output n newlines where n is replaced with an integer:
<nul set /p "=%\E%[nE"
Many
Please note that all solutions that use cursor positioning according to Console Virtual Terminal Sequences, Cursor Positioning with:
Sequence
Code
Description
Behaviour
ESC [ <n> E
CNL
Cursor Next Line
Cursor down <n> lines from current position
only work as long as the bottom of the console window is not reached.
At the bottom there is no space left to move the cursor down so it just moves left (with the CR of CRLF) and the line printed before is overwritten from its beginning.
To echo a newline, add a dot . right after the echo:
echo.
This worked for me, no delayed expansion necessary:
#echo off
(
echo ^<html^>
echo ^<body^>
echo Hello
echo ^</body^>
echo ^</html^>
)
pause
It writes output like this:
<html>
<body>
Hello
</body>
</html>
Press any key to continue . . .
You can use #echo ( #echo + [space] + [insecable space] )
Note: The insecable space can be obtained with Alt+0160
Hope it helps :)
[edit] Hmm you're right, I needed it in a Makefile, it works perfectly in there. I guess my answer is not adapted for batch files... My bad.
simple
set nl=.
echo hello
echo%nl%
REM without space ^^^
echo World
Result:
hello
world
Be aware, this won't work in console because it'll simulate an escape key and clear the line.
Using this code, replace <ESC> with the 0x1b escape character or use this Pastebin link:
:: Replace <ESC> with the 0x1b escape character or copy from this Pastebin:
:: https://pastebin.com/xLWKTQZQ
echo Hello<ESC>[Eworld!
:: OR
set "\n=<ESC>[E"
echo Hello%\n%world!
Adding a variant to Ken's answer, that shows setting values for environment variables with new lines in them.
We use this method to append error conditions to a string in a VAR, then at the end of all the error checking output to a file as a summary of all the errors.
This is not complete code, just an example.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:: the two blank lines are required!
set NLM=^
set NL=^^^%NLM%%NLM%^%NLM%%NLM%
:: Example Usage:
Set ErrMsg=Start Reporting:
:: some logic here finds an error condition and appends the error report
set ErrMsg=!ErrMsg!!NL!Error Title1!NL!Description!NL!Summary!NL!
:: some logic here finds another error condition and appends the error report
set ErrMsg=!ErrMsg!!NL!Error Title2!NL!Description!NL!Summary!NL!
:: some logic here finds another error condition and appends the error report
set ErrMsg=!ErrMsg!!NL!Error Title3!NL!Description!NL!Summary!NL!
echo %ErrMsg%
pause
echo %ErrMsg% > MyLogFile.log
Log and Screen output look like this...