Page 1 of 1

What does & mean?

Posted: 21 Aug 2018 07:43
by ahzong
As simple as the subject says, what does an ampersand (&) mean in batch programming?
All I know is it is located between two lines or commands, but I still don't get what it does exactly, and how it is used practically in code.
Thanks for answering!

Re: What does & mean?

Posted: 21 Aug 2018 07:52
by Squashman
Allows you to stack multiple commands on one line.

For example

Code: Select all

echo Batch files are cool. & echo Batch files are fun.
versus

Code: Select all

echo Batch files are cool.
echo Batch files are fun.

Re: What does & mean?

Posted: 21 Aug 2018 09:04
by ahzong
Thank you very much! :D

Re: What does & mean?

Posted: 21 Aug 2018 09:09
by dbenham
There is one other use of & that is totally unrelated to command concatenation.

& is used during redirection to specify an existing file handle.

For example, it is often desired to capture both stdout (file handle 1) and stderr (file handle 2) to a single logfile. This is easily done by redirecting stderr to the existing definition of stdout. But the reference to 1 (stdout) must be prefixed with & so that it is interpreted as a file handle instead of a file name.

Code: Select all

someCommand 2>&1

Dave Benham

Re: What does & mean?

Posted: 21 Aug 2018 17:41
by CirothUngol
Wait, isn't there also...
&& = execute following command only if previous command's errorlevel==0
|| = execute following command only if previous command' errorlevel<>0

So...
someCommand && doIfErrLev==0 || doIfErrLev<>0

...is analogous to:
someCommand
if errorlevel 1 (doIfErrLev<>0) ELSE (doIfErrLev==0)

Re: What does & mean?

Posted: 22 Aug 2018 06:20
by dbenham
CirothUngol wrote:
21 Aug 2018 17:41
Wait, isn't there also...
&& = execute following command only if previous command's errorlevel==0
|| = execute following command only if previous command' errorlevel<>0

So...
someCommand && doIfErrLev==0 || doIfErrLev<>0

...is analogous to:
someCommand
if errorlevel 1 (doIfErrLev<>0) ELSE (doIfErrLev==0)
Of course, how could I forget. But your definition is wrong - the && and || do not respond to ERRORLEVEL, but rather to the return code of the most recently executed command or operation - The return code and ERRORLEVEL are not quite the same thing :!:

Not all internal commands clear the ERRORLEVEL upon success. So it is actually a good thing that && and || do not respond to ERRORLEVEL.

In the example code below, (CALL ) with a space sets ERRORLEVEL to 0, and (CALL) without a space sets ERRORLEVEL to 1.

Code: Select all

@echo off
(call)
echo ERRORLEVEL is %errorlevel%&&The ECHO was successful||The ECHO failed
echo ERRORLEVEL is still %errolevel%
-- OUTPUT --

Code: Select all

ERRORLEVEL is 1
The previous ECHO was successful
ERRORLEVEL is still 1
If && and || responded to ERRORLEVEL then the middle line should read "The previous ECHO failed"

Not only that, but || can actually detect an error and set the ERRORLEVEL in situations that would not set ERRORLEVEL without it.

Code: Select all

@echo off
(call )
echo ERRORLEVEL = %ERRORLEVEL%
for /f %%A in ("") do echo No iterations
echo After empty FOR /F without ^|^|: ERRORLEVEL = %ERRORLEVEL%
(for /f %%A in ("") do echo No iterations) && echo There were iterations || echo There were no iterations
echo After empty FOR /F with ^|^|: ERRORLEVEL = %ERRORLEVEL%

echo(

(call )
echo ERRORLEVEL = %ERRORLEVEL%
<NotExists (
 rem
)
echo After failed redirection without ^|^|: ERRORLEVEL = %ERRORLEVEL%
<NotExists (
 rem
) && echo Redirection succeeded || echo Redirection failed
echo After failed redirection with ^|^|: ERRORLEVEL = %ERRORLEVEL%
--OUTPUT--

Code: Select all

ERRORLEVEL = 0
After empty FOR /F without ||: ERRORLEVEL = 0
There were no iterations
After empty FOR /F with ||: ERRORLEVEL = 1

ERRORLEVEL = 0
The system cannot find the file specified.
After failed redirection without ||: ERRORLEVEL = 0
The system cannot find the file specified.
Redirection failed
After failed redirection with ||: ERRORLEVEL = 1
In the last example, || is responding to the failed redirection, which is not really a command. That is why I say that && and || respond to the most recently executed command or operation.

=======================================

Lastly, since we are trying to be complete, & is also the bitwise AND operator when used in the SET /A command

Code: Select all

@echo off
setlocal
set /a "result=13 & 7"
echo 13 ^& 7 = %result%
echo(
echo in Binary:
echo 13 = 00000000000000000000000000001101
echo  7 = 00000000000000000000000000000111
echo  5 = 00000000000000000000000000000101
--OUTPUT--

Code: Select all

13 & 7 = 5

in Binary:
13 = 00000000000000000000000000001101
 7 = 00000000000000000000000000000111
 5 = 00000000000000000000000000000101
 

Dave Benham

Re: What does & mean?

Posted: 22 Aug 2018 07:14
by Aacini
dbenham wrote:
22 Aug 2018 06:20
CirothUngol wrote:
21 Aug 2018 17:41
Wait, isn't there also...
&& = execute following command only if previous command's errorlevel==0
|| = execute following command only if previous command' errorlevel<>0

So...
someCommand && doIfErrLev==0 || doIfErrLev<>0

...is analogous to:
someCommand
if errorlevel 1 (doIfErrLev<>0) ELSE (doIfErrLev==0)
Of course, how could I forget. But your definition is wrong - the && and || do not respond to ERRORLEVEL, but rather to the return code of the most recently executed command or operation - The return code and ERRORLEVEL are not quite the same thing :!:

Not all internal commands clear the ERRORLEVEL upon success. So it is actually a good thing that && and || do not respond to ERRORLEVEL.

In the example code below, (CALL ) with a space sets ERRORLEVEL to 0, and (CALL) without a space sets ERRORLEVEL to 1.

Code: Select all

@echo off
(call)
echo ERRORLEVEL is %errorlevel%&&The ECHO was successful||The ECHO failed
echo ERRORLEVEL is still %errolevel%
-- OUTPUT --

Code: Select all

ERRORLEVEL is 1
The previous ECHO was successful
ERRORLEVEL is still 1
If && and || responded to ERRORLEVEL then the middle line should read "The previous ECHO failed"

Not only that, but || can actually detect an error and set the ERRORLEVEL in situations that would not set ERRORLEVEL without it.

Code: Select all

@echo off
(call )
echo ERRORLEVEL = %ERRORLEVEL%
for /f %%A in ("") do echo No iterations
echo After empty FOR /F without ^|^|: ERRORLEVEL = %ERRORLEVEL%
(for /f %%A in ("") do echo No iterations) && echo There were iterations || echo There were no iterations
echo After empty FOR /F with ^|^|: ERRORLEVEL = %ERRORLEVEL%

echo(

(call )
echo ERRORLEVEL = %ERRORLEVEL%
<NotExists (
 rem
)
echo After failed redirection without ^|^|: ERRORLEVEL = %ERRORLEVEL%
<NotExists (
 rem
) && echo Redirection succeeded || echo Redirection failed
echo After failed redirection with ^|^|: ERRORLEVEL = %ERRORLEVEL%
--OUTPUT--

Code: Select all

ERRORLEVEL = 0
After empty FOR /F without ||: ERRORLEVEL = 0
There were no iterations
After empty FOR /F with ||: ERRORLEVEL = 1

ERRORLEVEL = 0
The system cannot find the file specified.
After failed redirection without ||: ERRORLEVEL = 0
The system cannot find the file specified.
Redirection failed
After failed redirection with ||: ERRORLEVEL = 1
In the last example, || is responding to the failed redirection, which is not really a command. That is why I say that && and || respond to the most recently executed command or operation.


Dave Benham


Just to complete this information, there are cases when a command ends with an ERRORLEVEL greater than 1 that does not means that the command failed because an error, but is just an indication of some condition.

Also, although || detect a "return code" caused by an error, it does not "set the ERRORLEVEL" by itself; this behavior depends on the type of command executed after the ||.

The ERRORLEVEL values returned by all internal cmd.exe commands are described at this SO question. Such a description is divided in tables accordingly to the different ways that the commands can change the ERRORLEVEL, including the commands and operations that cause a "return code" different than zero, and the commands that set the ERRORLEVEL in this case when they are placed after ||.

Antonio

Re: What does & mean?

Posted: 22 Aug 2018 08:26
by dbenham
Aacini wrote:
22 Aug 2018 07:14
Just to complete this information, there are cases when a command ends with an ERRORLEVEL greater than 1 that does not means that the command failed because an error, but is just an indication of some condition.
Fair point. A good example is the ERRORLEVEL returned by HELP.

Requesting HELP for an invalid command gives an error message, but returns ERRORLEVEL 0.
Requesting HELP for a valid command gives the requested help, but returns ERRORLEVEL 1.

Code: Select all

@echo off
help bogusCommand
echo ERRORLEVEL = %errorlevel%
help rem
echo ERRORLEVEL = %errorlevel%
--OUTPUT--

Code: Select all

This command is not supported by the help utility.  Try "bogusCommand /?".
ERRORLEVEL = 0
Records comments (remarks) in a batch file or CONFIG.SYS.

REM [comment]
ERRORLEVEL = 1

Aacini wrote:
22 Aug 2018 07:14
Also, although || detect a "return code" caused by an error, it does not "set the ERRORLEVEL" by itself; this behavior depends on the type of command executed after the ||.
That can't be right. Surely ECHO is not setting the ERRORLEVEL in my examples. The subsequent command does not matter, as long as it does not itself set ERRORLEVEL. However, I do agree that a command executed by || can mask the returned value of the previous command if the command after || itself sets ERRORLEVEL. I believe that is because || first sets the ERRORLEVEL based on the previous command's return code, and then the command after || may overwrite the ERRORLEVEL with its own value.

The value may not always be 0. For example:

Code: Select all

@echo off
(call )
REM
echo After REM: ERRORLEVEL = %ERRORLEVEL%
rd NotExists
echo After failed RD without ^|^|: ERRORLEVEL = %ERRORLEVEL%
rd NotExists || REM
echo After failed RD with ^|^|: ERRORLEVEL = %ERRORLEVEL%
--OUTPUT--

Code: Select all

After REM: ERRORLEVEL = 0
The system cannot find the file specified.
After failed RD without ||: ERRORLEVEL = 0
The system cannot find the file specified.
After failed RD with ||: ERRORLEVEL = 2
I claim that || always sets the ERRORLEVEL because of what happens when an invalid command is issued. This normally sets ERRORLEVEL to 9009, but if || is used, then the ERRORLEVEL becomes 1. I believe that the invalid command sets ERRORLEVEL to 9009, but has a return code of 1. The || then overwrites the 9009 ERRORLEVEL with the 1 return code. Note the use of CMD /C below, based on an idea by jeb. CMD /C returns an error code, not ERRORLEVEL. This gives additional evidence that the return code of an invalid command is 1, even though the ERRORLEVEL is 9009.

Code: Select all

@echo off
(call )
bogusCommand
echo After invalid command without ^|^|: ERRORLEVEL = %ERRORLEVEL%
(call )
bogusCommand || REM
echo After invalid command with ^|^|: ERRORLEVEL = %ERRORLEVEL%
(call )
cmd /c "bogusCommand"
echo After bogusCommand executed by CMD /C: ERRORLEVEL = %ERRORLEVEL%
(call )
cmd /c "exit /b 9009"
echo Prove that CMD /C can return 9009: ERRORLEVEL = %ERRORLEVEL%
--OUTPUT--

Code: Select all

'bogusCommand' is not recognized as an internal or external command,
operable program or batch file.
After invalid command without ||: ERRORLEVEL = 9009
'bogusCommand' is not recognized as an internal or external command,
operable program or batch file.
After invalid command with ||: ERRORLEVEL = 1
'bogusCommand' is not recognized as an internal or external command,
operable program or batch file.
After bogusCommand executed by CMD /C: ERRORLEVEL = 1
Prove that CMD /C can return 9009: ERRORLEVEL = 9009

Dave Benham