2012-03-06 18 views
7

En una subrutina DOS de archivo por lotes, ¿cómo puedo desactivar el eco dentro de la subrutina, pero antes de volver, volver a ponerlo como estaba antes (encendido o apagado)?restablecer el estado de eco anterior

Por ejemplo, si había un comando llamado echo restore, usaría así:

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 

Respuesta

2

La forma más sencilla es no gire ECHO fuera en el primer lugar.

En su lugar, haga lo que hace actualmente con la línea echo off con el resto de su subrutina - prefija todos los comandos en la subrutina con un signo @. Esto tiene el efecto de desactivar el eco para ese comando, pero mantiene el estado del eco para futuros comandos.

Si utiliza comandos que ejecutan otros comandos, como IF o DO, también deberá poner un prefijo "subcomando" con un @ para evitar que se impriman cuando el eco esté activado.

5

Mi primer intento fue una falla total - gracias jeb por señalar los errores. Para aquellos que están interesados, la respuesta original está disponible en el historial de edición.

Aacini tiene una buena solución si no le importa poner su subrutina en un archivo separado.

Aquí hay una solución que funciona sin necesidad de un segundo archivo por lotes. ¡Y realmente funciona esta vez! :)

(Edición 2 - código optimizado según la sugerencia de Jeb en el comentario)

: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 
) 

Si usted está dispuesto a soportar el riesgo leve de dos procesos al mismo tiempo tratando de acceder al mismo archivo, el: La rutina getEchoState se puede simplificar sin la necesidad de SETLOCAL o una 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 
) 
+2

¡Buena idea, pero no puede funcionar! Como el 'echo' en' for/f "tokens = 3 delims =." %% A in ('echo') 'se ejecutará en un nuevo contexto cmd y siempre estará 'ON'. El segundo problema es que incluso si obtienes el estado está localizado, como en mi sistema obtuve 'ECHO ist eingeschaltet (ON) .' – jeb

+0

Por supuesto que estás en lo correcto, maldita sea :) La peor parte es que ya había descubierto todo de esto hace mucho tiempo (a excepción del problema alemán), ¡y se olvidó! Voy a venir con una versión de trabajo. – dbenham

+0

Puede usar la redirección 'echo> tmpfile.tmp' y luego usar un FOR-loop. Quizás el último token esté siempre ON/OFF o (ON)/(OFF) – jeb

3

La forma más fácil es extraer la subrutina a otro archivo .bat y llamarlo a través CMD /CCALL lugar de esta manera:

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 

Este forma en que el estado del eco será automáticamente restaurado al valor que tenía cuando se ejecutó el CMD /C ed; el único inconveniente de este método es una ejecución ligeramente más lenta ...

+0

por favor revisa mi edición – JoelFan

1

Aquí hay una solución directa que se basa en un solo archivo temporal (utilizando% random% para evitar condiciones de carrera). Funciona y es al menos la localización resistente, es decir, funciona para los dos casos conocidos establecidos por @JoelFan y @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 

añadir este código preliminar para aumentar la robustez de la solución (a pesar de los años impares son altas de que no es necesario):

 
@:: 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) 
0

que estaba buscando la misma solución al mismo problema, y ​​después de leer sus comentarios tuve una idea (que no es la respuesta a la pregunta, pero mi problema es aún mejor).

que no estaba satisfecho con el cmd.exe /c mysub.cmd, ya que hace difícil o incluso imposible volver las variables (No vi) - (no podía comentar porque es la primera vez que publico aquí :)

lugar se dio cuenta de que lo único que queremos es -en final- para suprimir la salida estándar:

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 

funciona bien con subrutinas etiquetados, con subrutinas contenidas en .cmd, y supongo que funcionaría correctamente incluso si el cmd.exe/c variante (o inicio). También tiene la ventaja de que podemos mantener o descartar la stderr, en sustitución de >nul con >nul 2>&1

observo que ss64.com scares niños como yo que indica que la llamada "redirección con & | <> también no funciona tan esperado ". Esta prueba simple funciona como se esperaba. Él debe haber estado pensando en situaciones más complejas.

1

No estuve muy contento con la solución anterior, especialmente por el problema del idioma, y ​​encontré una muy simple simplemente comparando el resultado de la configuración actual del eco con el resultado cuando se desactiva explícitamente. Así es como funciona:

:: 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 
Cuestiones relacionadas