2012-03-06 42 views
7

Trong một chương trình con DOS Batch File, làm thế nào tôi có thể tắt tiếng vang trong chương trình con, nhưng trước khi quay trở lại, hãy đặt nó trở về trước (hoặc tắt hoặc bật)?khôi phục trạng thái echo trước đó

Ví dụ, nếu có một lệnh gọi echo restore, tôi sẽ sử dụng nó như thế này:

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 

Trả lời

2

Cách đơn giản nhất là không bật echo off ở nơi đầu tiên.

Thay vào đó, hãy làm những gì bạn hiện đang thực hiện với dòng echo off cho phần còn lại của chương trình con của bạn - tiền tố tất cả các lệnh trong chương trình con có ký hiệu @. Điều này có tác dụng tắt tiếng vang cho lệnh đó, nhưng giữ trạng thái echo cho các lệnh trong tương lai.

Nếu bạn sử dụng lệnh thực hiện các lệnh khác, như IF hoặc DO, bạn cũng sẽ cần thêm tiền tố "tiểu thư" bằng @ để giữ cho chúng không được in khi có tiếng vang khác.

5

Lần thử đầu tiên của tôi là thất bại hoàn toàn - cảm ơn vì đã chỉ ra lỗi. Đối với những người quan tâm, câu trả lời gốc có sẵn trong lịch sử chỉnh sửa.

Aacini có giải pháp tốt nếu bạn không ngại đưa chương trình con của mình vào một tệp riêng biệt.

Dưới đây là giải pháp hoạt động mà không cần tệp đợt 2. Và nó thực sự hoạt động lần này! :)

(Chỉnh sửa 2 - tối ưu hóa mã theo đề nghị của Jeb trong 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 
) 

Nếu bạn sẵn sàng đưa lên với nguy cơ nhẹ của hai quá trình đồng thời cố gắng truy cập cùng một tập tin, các: getEchoState thường có thể được đơn giản hóa mà không cần SETLOCAL hoặc biến tạm thời.

: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

Ý tưởng hay nhưng không thể hoạt động! Khi 'echo' trong' for/f 'tokens = 3 delims =. "%% A in (' echo ')' sẽ được thực hiện trong một ngữ cảnh cmd mới và luôn luôn là 'ON'. Vấn đề thứ hai là ngay cả khi bạn nhận được trạng thái nó đã được bản địa hóa, như trên hệ thống của tôi, tôi có 'ECHO ist eingeschaltet (ON). ' – jeb

+0

Tất nhiên bạn đúng, chết tiệt :) Phần tồi tệ nhất là, tôi đã khám phá tất cả của điều này một thời gian dài trước đây (ngoại trừ vấn đề của Đức), và quên! Tôi sẽ đưa ra một phiên bản làm việc. – dbenham

+0

Bạn có thể sử dụng chuyển hướng 'echo> tmpfile.tmp' và sau đó sử dụng vòng lặp FOR. Có lẽ mã thông báo cuối cùng luôn là ON/OFF hoặc (ON)/(OFF) – jeb

3

Cách đơn giản nhất là để trích xuất các chương trình con để một file .bat và gọi nó qua CMD /C thay vì CALL theo cách này:

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 

này cách trạng thái echo sẽ là tự động được khôi phục về giá trị khi có CMD /C là thực thi ed; hạn chế duy nhất của phương pháp này là thực thi hơi chậm hơn ...

+0

vui lòng kiểm tra chỉnh sửa của tôi – JoelFan

1

Đây là giải pháp chuyển tiếp thẳng dựa trên một tệp tạm thời (sử dụng% random% để tránh điều kiện chủng tộc). Nó hoạt động và ít nhất là nội địa hóa kháng, tức là, nó hoạt động cho hai trường hợp đã biết được nêu bởi @JoelFan và @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 

Thêm mã sơ bộ này để tăng độ bền của giải pháp (mặc dù của lẻ là cao mà nó không cần thiết):

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

tôi đang tìm kiếm các giải pháp tương tự cho cùng một vấn đề, và sau khi đọc ý kiến ​​của bạn tôi đã có một ý tưởng (đó không phải là câu trả lời cho câu hỏi, nhưng đối với vấn đề của tôi thậm chí còn tốt hơn).

tôi đã không hài lòng với cmd.exe /c mysub.cmd vì nó làm cho cứng hoặc thậm chí không thể quay trở lại các biến (tôi đã không kiểm tra) - (không thể bình luận vì đây là lần đầu tiên tôi gửi ở đây :)

Thay vào đó nhận thấy rằng tất cả chúng ta muốn -trong thúc- là để ngăn chặn 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 

nó hoạt động tốt với các chương trình con dán nhãn, với các chương trình con chứa trong file .cmd, và tôi cho rằng nó sẽ hoạt động tốt ngay cả với các cmd.exe/c biến thể (hoặc bắt đầu). Nó cũng có các cộng mà chúng ta có thể giữ lại hoặc loại bỏ các stderr, thay thế >nul với >nul 2>&1

tôi lưu ý rằng ss64.com scares đứa trẻ như tôi nói rằng với cuộc gọi "Redirection với & | <> cũng không hoạt động như dự kiến ​​". Bài kiểm tra đơn giản này hoạt động như mong đợi. Anh hẳn đã nghĩ đến những tình huống phức tạp hơn.

1

Tôi đã không thực sự hài lòng với giải pháp trên đặc biệt vì vấn đề ngôn ngữ và tôi đã tìm thấy một cách rất đơn giản chỉ bằng cách so sánh kết quả từ cài đặt echo hiện tại với kết quả khi đặt rõ ràng TẮT. Đây là cách hoạt động:

:: 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 
Các vấn đề liên quan