在DOS Batch File子程序中,如何在子程序中关闭echo,但在返回之前,将其恢复到以前的状态(打开或关闭)?
例如,如果有一个名为echo restore
的命令,我会像这样使用它:
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
答案 0 :(得分:5)
我的第一次尝试是完全失败 - 感谢jeb指出错误。对于那些感兴趣的人,原始答案可以在编辑历史中找到。
如果您不介意将子程序放在单独的文件中,Aacini有一个很好的解决方案。
这是一个无需第二批文件即可运行的解决方案。它实际上这次工作! :)
(根据jeb在评论中的建议编辑2 - 优化代码)
: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
)
如果您愿意忍受同时尝试访问同一文件的两个进程的轻微风险,则可以简化:getEchoState例程,而无需SETLOCAL或临时变量。
: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
)
答案 1 :(得分:4)
最简单的方法是将子例程提取到另一个.bat文件,并通过CMD /C
而不是CALL
以这种方式调用它:
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
这样,回显状态将自动恢复为执行CMD /C
时的值;这种方法的唯一缺点是执行速度稍慢......
答案 2 :(得分:2)
最简单的方法是首先不要关闭回声。
相反,使用echo off
行执行当前对子例程的其余部分执行的操作 - 在子例程中使用@
符号作为前缀。这具有关闭该命令的回声的效果,但保留未来命令的回声状态。
如果使用执行其他命令的命令(如IF或DO),则还需要在“子命令”前加上@,以防止在打开echo时打印它们。
答案 3 :(得分:1)
这是一个直接的解决方案,它依赖于一个临时文件(使用%random%来避免竞争条件)。它起作用并且至少是本地化抗性,即它适用于@JoelFan和@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
添加此初步代码以提高解决方案的稳健性(尽管奇数很高,但没有必要):
@:: 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 )
答案 4 :(得分:1)
由于语言问题,我对上述解决方案并不满意,只是通过将当前回声设置的结果与显式设置为OFF时的结果进行比较,我发现了一个非常简单的问题。这是它的工作原理:
:: 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
答案 5 :(得分:0)
我正在为同样的问题找到相同的解决方案,在阅读你的评论后我有了一个想法(这不是问题的答案,但我的问题更好)。
我对cmd.exe /c mysub.cmd
不满意,因为它很难甚至不可能返回变量(我没有检查) - (无法评论,因为这是我第一次在这里发帖:)
相反注意到我们想要的一切 - 最终 - 是压制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
它对标记的子例程工作正常,子例程包含在.cmd文件中,我想它即使使用cmd.exe / c变体(或启动)也能正常工作。
它还有一个优点,我们可以保留或丢弃stderr,用>nul
替换>nul 2>&1
我注意到像我这样的ss64.com scares小孩说,通过电话“重定向与& |<>也无法按预期工作”。 这个简单的测试按预期工作。他一定是在考虑更复杂的情况。