Batch file 恢复以前的回显状态
在DOS批处理文件子例程中,如何在子例程中关闭echo,但在返回之前,将其恢复到以前的状态(打开或关闭) 例如,如果有一个名为Batch file 恢复以前的回显状态,batch-file,subroutine,Batch File,Subroutine,在DOS批处理文件子例程中,如何在子例程中关闭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 restor
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
最简单的方法是首先不要关闭回声
相反,执行当前对子例程其余部分执行的echo off
行操作-在子例程中的所有命令前面加上@
符号。这样做的效果是关闭该命令的回显,但为将来的命令保留回显状态
如果您使用执行其他命令的命令,如If或DO,您还需要在“子命令”前面加上@,以防止在echo打开时打印这些命令。我的第一次尝试完全失败-感谢jeb指出错误。对于感兴趣的人,可以在编辑历史记录中找到原始答案 如果您不介意将子程序放在单独的文件中,Aacini有一个很好的解决方案 这是一个不需要第二批文件的解决方案。这一次它真的起作用了!:) (根据jeb在评论中的建议编辑2-优化代码) 如果您愿意忍受两个进程同时尝试访问同一文件的轻微风险,那么:getEchoState例程可以简化,而不需要SETLOCAL或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
)
最简单的方法是将子例程提取到另一个.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
时的值;此方法的唯一缺点是执行速度稍慢…这里有一个直接的解决方案,它依赖于单个临时文件(使用%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
@设置\uu ME\u tempfile=%temp%\%~nx0.echo状态。%random%。%random%.txt
@设置“我的回声”=关闭
@echo>“%\uuuuMe\uTempFile%”
@键入“%\uuu ME\u tempfile%”numl@“%SystemRoot%\System32\findstr”/i/r“[(]*on[)]*\.$”>
@如果“%ERRORLEVEL%”==“0”(设置为启用)
@擦除“%\u ME\u tempfile%”nul
@::echo\uuuuMe\uEcho=%\uuuMe\uEcho%
@回音
...
endlocal和echo%\uuuMe\uEcho%
@后藤:EOF
添加此初步代码以提高解决方案的健壮性(尽管奇数很高,因此不需要):
@::定义临时路径
@如果未定义温度(@set“temp=%tmp%”)
@如果不存在“%temp%”(@set“temp=%tmp%”)
@如果不存在“%temp%”(@set“temp=%LocalAppData%\temp”)
@如果不存在“%temp%”(@exit/b-1)
:uu ME_ufind_utempfile
@设置\uu ME\u tempfile=%temp%\%~nx0.echo状态。%random%。%random%.txt
@如果存在“%\u ME\u tempfile%”(转到:\u ME\u find\u tempfile)
我一直在寻找相同问题的相同解决方案,在阅读了您的评论后,我有了一个想法(这不是问题的答案,但对于我的问题来说更好) 我对
cmd.exe/cmysub.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变量(或start)。
它还有一个优点,就是我们可以保留或丢弃stderr,将>nul
替换为>nul2>&1
我注意到,像我这样的ss64.com孩子说,使用call“使用&|重定向也不能按预期工作”。
这个简单的测试工作正常。他一定考虑过更复杂的情况。我对上述解决方案不太满意,特别是因为语言问题,我只需将当前回声设置的结果与显式设置的结果进行比较,就发现了一个非常简单的问题。这就是它的工作原理:
:: 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
好主意,但不行!由于('echo')中的
echo
将在新的cmd上下文中执行,并且始终处于打开状态。第二个问题是,即使你得到了它的本地化状态,就像在我的系统上一样,我得到了ECHO ist eingeschaltet(on)。
当然你是对的,该死:)最糟糕的是,我早就发现了这一切(除了德国问题),然后忘记了!我将提供一个工作版本。您可以使用重定向echo>tmpfile.tmp
,然后使用FOR循环。也许最后一个令牌总是开/关或(开)/(关)现在调用:getEchoState2
可以优化为FOR%%A in(dummy)do rem
,因此在调试期间不需要调用/标签,您希望看到打印的命令,但在发布后就不需要了。将许多奇数放置的@
换入换出有点像维护噩梦。
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
:: 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