Why doesn't @ECHO ON/OFF work within a batch file IF block?

As you have discovered, the changed ECHO state is not recognized by the parser until it reaches a statement that is after the code block that contains the ECHO ON/OFF.

But there is one exception - the commands after FOR ... DO do take on the state change within the same block :-)

Note that you only need @ to suppress command output when ECHO is currently ON. If it is OFF, then there is no need for @ECHO ON. And if you turn it ON and OFF within the same code block, then you don't need it there either.

Here is a demo that echos the even test lines:

@echo off
echo Test #1
(
  echo on
  for %%. in (.) do echo Test #2
  echo off
  echo Test #3
  echo on
  for %%. in (.) do echo Test #4
  echo off
  echo Test #5
)
echo on
echo Test #6
@echo off
echo Test #7

-- OUTPUT --

Test #1

C:\test>echo Test #2
Test #2
Test #3

C:\test>echo Test #4
Test #4
Test #5

C:\test>echo Test #6
Test #6
Test #7

You might find it convenient to declare a simple echo_on "macro". The following produces the exact same output:

@echo off
setlocal

set "echo_on=echo on&for %%. in (.) do"

echo Test #1
(
  %echo_on% echo Test #2
  echo off
  echo Test #3
  %echo_on% echo Test #4
  echo off
  echo Test #5
)
echo on
echo Test #6
@echo off
echo Test #7

Have just found out what is causing this by turning the echo on before an if block.

@echo on
if 1 == 1 (
  echo Test #1
  echo Test #2
)

This outputs:

C:\mybatchfilelocation>if 1 == 1 (
echo Test #1
echo Test #2
)
Test #1
Test #2

So the statement that is echoed is the entire if block rather than each statement within it. This answer explains this further and this answer gives a workaround - unfortunately not what I wanted to hear but it looks like lots of gotos and labels may be the only workable solution.


You could do something like this to achieve the result you want:

@echo off
set "ExecuteCmd=echo Test #2"
echo Test #1
if 1 == 1 (
  echo %ExecuteCmd%
  %ExecuteCmd%
  echo Test #3
)
@echo on
echo Test #4