2016-01-18 27 views
6

@echo on e @echo off non sembrano avere alcun effetto quando vengono eseguiti all'interno di un blocco tra parentesi if in un file batch. Ecco un semplice demo:Perché @ECHO ON/OFF non funziona all'interno di un file batch blocco IF?

@echo off 
echo Test #1 
if 1 == 1 (
    @echo on 
    echo Test #2 
    @echo off 
    echo Test #3 
) 
@echo on 
echo Test #4 

L'uscita dalla esecuzione di cui sopra sulla riga di comando è:

Test # 1
Test # 2
Test # 3
C: \ mybatchfilelocation> echo test # 4
test # 4

qualcuno potrebbe spiegare questo e/o r suggerire una soluzione alternativa? (si aspettano che potrebbe probabilmente essere risolto con l'uso abbondante di goto ed etichette ma preferirebbero continuare ad utilizzare parentesi, se blocchi se possibile ...)

+0

Penso che sia perché lo stato corrente "echo on/off" ha effetto solo sull'intera linea o blocco; se vuoi controllarlo individualmente per ciascun comando, imposta "echo on" e precedi ogni comando che vuoi nascondere con '@'; – aschipfl

+0

Grazie, ma sfortunatamente sembra che echo on non esegua comandi echi tra parentesi (vedi la mia risposta appena aggiunta sotto). –

+0

Non capisco, entrambi echo's nella tua risposta _are_ 'echo'ed; metti '@' prima di uno degli 'echo's per nasconderlo; metti '@' davanti a '(' per nascondere tutto dopo 'if' ... – aschipfl

risposta

5

Come avete scoperto, lo stato ECHO cambiato non è riconosciuto dal parser fino a raggiungere una dichiarazione che è dopo il blocco di codice che contiene l'ECHO ON/OFF.

Ma c'è un'eccezione: i comandi dopo FOR ...FARE il cambio di stato nello stesso blocco :-)

Nota che è necessario solo @ per sopprimere l'output del comando quando ECHO è attualmente ON. Se è OFF, non è necessario per @ECHO ON. E se lo si accende e si spegne nello stesso blocco di codice, non è necessario neanche lì.

Ecco una demo che echos le linee anche di prova:

@echo off 
echo Test #1 
(
    echo on 
    for %%. in (.) do echo Test #2 
    echo off 
    echo Test #3 
    echo on 
    for %%. in (.) do echo Test #4 
    echo off 
    echo Test #5 
) 
echo on 
echo Test #6 
@echo off 
echo Test #7 

- USCITA -

Test #1 

C:\test>echo Test #2 
Test #2 
Test #3 

C:\test>echo Test #4 
Test #4 
Test #5 

C:\test>echo Test #6 
Test #6 
Test #7 

Si potrebbe trovare conveniente dichiarare un semplice echo_on "macro". Quello che segue produce esattamente lo stesso risultato:

@echo off 
setlocal 

set "echo_on=echo on&for %%. in (.) do" 

echo Test #1 
(
    %echo_on% echo Test #2 
    echo off 
    echo Test #3 
    %echo_on% echo Test #4 
    echo off 
    echo Test #5 
) 
echo on 
echo Test #6 
@echo off 
echo Test #7 
+0

Ottima risposta e bel trucco! Solo una cosa, sai qualcosa del settore interno - vale a dire perché 'FOR' ...' DO' è l'eccezione alla regola? –

+1

@SteveChambers - Suppongo perché FOR è l'unico comando di ECHO più volte. Il primo ECHO per l'intera dichiarazione FOR viene soppresso. Ma i comandi DO sono successivamente ECHOed una volta per ogni iterazione. Vedi http://stackoverflow.com/a/4095133/1012053 per maggiori informazioni. – dbenham

1

appena scoperto cosa sta causando questo girando l'eco sulla prima un blocco if.

@echo on 
if 1 == 1 (
    echo Test #1 
    echo Test #2 
) 

Questo uscite:

C: \ mybatchfilelocation> se 1 == 1 (
eco Test # 1
test echo # 2
)
Test # 1
di prova # 2

Quindi la dichiarazione che è ech oed è l'intero se il blocco piuttosto che ciascuna istruzione al suo interno. This answer lo spiega ulteriormente e this answer offre una soluzione alternativa - sfortunatamente non è quello che volevo sentire ma sembra un sacco di goto s e le etichette potrebbero essere l'unica soluzione praticabile.

+1

Nella mia esperienza, creare un "blocco" con parentesi non è proprio come fare una cosa simile in un vero linguaggio di programmazione perché l'intera cosa viene analizzata/var-sostituita in una volta prima che sia mai stata eseguita. lo faresti, mi sarei aspettato che funzionasse come hai fatto tu, ma non posso dire di essere sorpreso di vedere un comportamento bizzarro su cmd/if. – mojo

+1

Questo comportamento è lo stesso che richiedeva un'espansione ritardata per accedere alle variabili modificate all'interno di un blocco: se "echo on' _before_ il blocco, tutte le righe nel blocco verranno mostrate anche se si inserisce un" echo off "al suo interno, e vice versa: se "echo off" prima del blocco, tutte le linee non verranno mostrate anche con un "echo on" all'interno del blocco. L'ultimo stato dell'eco viene utilizzato nella prima riga dopo il blocco. – Aacini

2

Si potrebbe fare qualcosa di simile per ottenere il risultato desiderato:

@echo off 
set "ExecuteCmd=echo Test #2" 
echo Test #1 
if 1 == 1 (
    echo %ExecuteCmd% 
    %ExecuteCmd% 
    echo Test #3 
) 
@echo on 
echo Test #4 
+0

Non è un cattivo tentativo in alternativa, ma dal momento che ci sono molti possibili comandi che possono essere eseguiti all'interno di un blocco "if", sembra che goto's e le etichette saranno più pratici. –

1

ne dici di mettere i comandi di controllo eco all'interno di una subroutine?

@echo off 
echo Test #1 
if 1 == 1 (
    CALL :DO_ECHO_ON 
    echo Test #3 
) 
@echo on 
echo Test #4 

@EXIT /B 

:DO_ECHO_ON 
@ECHO ON 
echo Test #2 
@ECHO OFF 
@EXIT /B 

Produce l'output che mi aspetto dalla descrizione.

Test #1 

C:\secret>echo Test #2 
Test #2 
Test #3 

C:\secret>echo Test #4 
Test #4 

Sulla base di uno dei tuoi commenti, suppongo che tu voglia essere in grado di attivare l'eco per i comandi arbitrari. Questa versione modificata lo fa.

@echo off 
echo Test #1 
if 1 == 1 (
    CALL :DO_ECHO_ON_CMD echo Test #2 
    echo Test #3 
    CALL :DO_ECHO_ON_CMD dir /b "C:\Program Files" 
    echo Test #3.1 
    CALL :DO_ECHO_ON_CMD attrib c:\Windows 
) 
@echo on 
echo Test #4 

EXIT /B 

:DO_ECHO_ON_CMD 
@ECHO ON 
%* 
@ECHO OFF 
@EXIT /B 0