Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Batch file 恢复以前的回显状态_Batch File_Subroutine - Fatal编程技术网

Batch file 恢复以前的回显状态

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

在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 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