Restore previous echo state

In the DOS Batch File subroutine, how can I turn off the echo in the subroutine, but before returning it back to what it was before (either on or off)?

For example, if there was a command called echo restore , I would use it as follows:

 echo on ... do stuff with echoing ... call :mySub ... continue to do stuff with echoing ... exit /b :mySub @echo off ... do stuff with no echoing ... echo restore goto :EOF 
+7
source share
6 answers

My first attempt was a complete failure - thanks jeb for pointing out the errors. For those who are interested, the original answer is available in the edit history.

Aacini has a good solution if you don't mind putting your subroutine in a separate file.

Here is a solution that works without the need for a second batch file. And it actually works this time! :)

(Edit 2 - optimized code as suggested by jeb in the comment)

 :mysub ::Silently get the echo state and turn echo off @( setlocal call :getEchoState echoState echo off ) ::Do whatever set return=returnValue ::Restore the echo state, pass the return value across endlocal, and return ( endlocal echo %echoState% set return=%return% exit /b ) :getEchoState echoStateVar @setlocal @set file=%time% @set file="%temp%\getEchoState%file::=_%_%random%.tmp" @( for %%A in (dummy) do rem ) >%file% @for %%A in (%file%) do @( endlocal if %%~zA equ 0 (set %~1=OFF) else set %~1=ON del %file% exit /b ) 

If you are willing to put up with a small risk of two processes at the same time, trying to access the same file, you can: simplify the procedure: getEchoState without the need to use SETLOCAL or the variable temp.

 :getEchoState echoStateVar @( for %%A in (dummy) do rem ) >"%temp%\getEchoState.tmp" @for %%A in ("%temp%\getEchoState.tmp") do @( if %%~zA equ 0 (set %~1=OFF) else set %~1=ON del "%temp%\getEchoState.tmp" exit /b ) 
+5
source

The easiest way is to extract the subroutine into another .bat file and call it via CMD /C instead of CALL as follows:

 echo on ... do stuff with echoing ... cmd /C mySub ... continue to do stuff with echoing ... exit /b 

mySub.bat:

 @echo off ... do stuff with no echoing ... exit /b 

Thus, the echo status will be automatically restored to the value that was during CMD /C ; the only drawback of this method is a slightly slower execution ...

+3
source

The easiest way is to not turn on the echo first.

Instead, do what you are doing now with the echo off line, the rest of your routine — the prefix of all commands in the routine is @ . This disables the echo for this command, but retains the echo state for future commands.

If you use commands that execute other commands, such as IF or DO, you will also need to prefix the “subcommands” with @ so that they do not print unless the echo is turned on otherwise.

+2
source

Here is a direct solution that relies on a single temporary file (using% random% to avoid race conditions). It works and is at least resistant to localization, i.e. Works for two well-known cases described by @JoelFan and @jeb.

  @set __ME_tempfile =% temp% \% ~ nx0.echo-state.% random%.% random% .txt
 @set __ME_echo = OFF
 @echo> "% __ ME_tempfile%"
 @type "% __ ME_tempfile%" |  @ "% SystemRoot% \ System32 \ findstr" / i / r "[(] * on [)] * \. $"> Nul
 @if "% ERRORLEVEL%" == "0" (set __ME_echo = ON)
 @erase "% __ ME_tempfile%"> nul
 @ :: echo __ME_echo =% __ ME_echo%
 @echo off
 ...
 endlocal & echo% __ ME_echo%
 @goto: EOF

Add this preliminary code to increase the reliability of the solution (although the odd ones are high, which is not necessary):

  @ :: define TEMP path
 @if NOT DEFINED temp (@set "temp =% tmp%")
 @if NOT EXIST "% temp%" (@set "temp =% tmp%")
 @if NOT EXIST "% temp%" (@set "temp =% LocalAppData% \ Temp")
 @if NOT EXIST "% temp%" (@exit / b -1)
 : __ ME_find_tempfile
 @set __ME_tempfile =% temp% \% ~ nx0.echo-state.% random%.% random% .txt
 @if EXIST "% __ ME_tempfile%" (goto: __ ME_find_tempfile)
+1
source

I was not happy with the solution above, especially due to a problem with the language, and I found a very simple example comparing the result with the current echo setting with the result when OFF is explicitly set. Here's how it works:

 :: SaveEchoSetting :: ::::::::::::::::::::::::::: :: Store current result @echo> %temp%\SEScur.tmp :: Store result when explicitly set OFF @echo off @echo> %temp%\SESoff.tmp :: If results do not match, it must have been ON ... else it was already OFF @for /f "tokens=*" %%r in (%temp%\SEScur.tmp) do ( @find "%%r" %temp%\SESoff.tmp > nul @if errorlevel 1 ( @echo @echo on > %temp%\SESfix.bat ) else ( @echo @echo off > %temp%\SESfix.bat ) ) :: :: Other code comes here :: Do whatever you want with echo setting ... :: :: Restore echo setting @call %temp%\SESfix.bat 
+1
source

I was looking for the same solution to the same problem, and after reading your comments I had an idea (this is not an answer to the question, but for my problem it is even better).

I am not happy with cmd.exe /c mysub.cmd because it makes it difficult or even impossible to return variables (I did not check) - (could not comment, because this is the first time I post here :)

Instead, they noticed that all we want - at the end - is to suppress stdout:

 echo on rem call "mysub.cmd" >nul call :mysub >nul echo %mysub_return_value% GOTO :eof :mysub setlocal set mysub_return_value="ApplePie" endlocal & set mysub_return_value=%mysub_return_value% GOTO :eof 

It works great with labeled routines with routines contained in .cmd files, and I believe that it will work fine even with the cmd.exe / c option (or run). It also has a plus that we can save or throw away stderr by replacing >nul with >nul 2>&1

I note that ss64.com scares kids like me, stating that with the call, “Redirecting with and | <> also doesn't work properly.” This simple test works as expected. He must have thought of more difficult situations.

0
source

All Articles