2011-12-12 12 views
14

Se prendo il seguente codice del lotto di Windows frammento ed eseguirlo:(Windows batch) Goto nel blocco if si comporta in modo molto strano

echo foo 
if 1 == 1 (
    echo bar 
    goto asdf 
    :asdf 
    echo baz 
) else (
    echo quux 
)

L'uscita mi aspetterei è:

foo 
bar 
baz

Ma invece ottengo:

foo 
bar 
baz 
quux

Se io commento la linea goto asdf, dà l'uscita mi aspetto. La riga echo quux non dovrebbe mai essere esecretata, quindi perché l'esistenza del goto sta provocando che ciò accada?

UPDATE: Per quello che vale, ecco una soluzione che fa correttamente quello che originariamente destinati:

goto BEGIN 

:doit 
    echo bar 
    goto asdf 
    :asdf 
    echo baz 
    goto :EOF 

:BEGIN 

echo foo 
if 1 == 1 (
    call :doit 
) else (
    echo quux 
)

Tuttavia, questo non risponde alla mia domanda iniziale.

risposta

23

L'obiettivo di una CHIAMATA o GOTO non deve mai essere all'interno di un'istruzione di blocco tra parentesi. Può essere fatto, ma come vedi, i risultati probabilmente non saranno ciò che desideri.

L'intero costrutto IF (...) ELSE (...) viene analizzato e caricato in memoria prima che venga elaborato. In altre parole, è logicamente trattato come una riga di codice. Dopo che è stato analizzato, CMD.EXE è in attesa di riprendere l'analisi a partire dalla riga successiva dopo il costrutto IF/ELSE.

Dopo la fase di analisi, il comando complesso viene eseguito dalla memoria. La clausola IF viene elaborata correttamente e la clausola ELSE viene saltata correttamente. MA all'interno della clausola IF (true), si esegue un GOTO :asdf, quindi CMD.EXE inizia a eseguire la scansione dell'etichetta. Inizia alla fine dell'IF/ELSE e scansiona fino alla fine del file, torna all'inizio e esegue la scansione finché non trova l'etichetta. L'etichetta si trova all'interno della tua clausola IF, ma lo scanner etichetta non sa nulla di quel dettaglio. Pertanto, quando il comando complesso termina l'esecuzione dalla memoria, l'elaborazione batch riprende dall'etichetta anziché dalla fine del complesso IF/ELSE.

Quindi a questo punto il processore batch vede ed esegue le prossime righe

echo baz 
) else (
    echo quux 
) 

Baz fa eco, e così è quux. Ma si potrebbe chiedere: "Perché non lo fa ) else ( e/o ) generare un errore di sintassi poiché sono ormai sbilanciato e non è più analizzato come parte della più ampia istruzione IF?

Questo è causa di come è gestita ).

Se v'è un open ( attivo quando si incontra ), poi il ) viene elaborato come ci si aspetterebbe.

Ma se il parser si aspetta un comando e trova un ) quando non v'è un attivo aperto (, quindi lo ) viene ignorato e tutti i caratteri sul resto della riga vengono ignorati! In effetti il ​​) ora funziona come una dichiarazione REM.

+2

+1 Buona spiegazione, Dave. Uno più corto è: quando viene eseguito 'GOTO' qualsiasi comando * attivo *' FOR/IF' viene annullato e il file Batch continua dall'etichetta. – Aacini

5

Qualsiasi cosa all'interno di una serie di parentesi viene considerata come una singola riga, elaborata, interpretata ed eseguita in un colpo solo.Lo script raggiunge goto asdf e salta fuori da quel blocco/linea. Sull'etichetta :asdf non c'è alcuna parentesi, quindi inizia a leggere le righe una per una. Raggiunge lo else, ma non c'è lo if tra :asdf e else, quindi lo ignora.

per evitare problemi come questo, io uso sempre goto o call su if e for dichiarazioni, piuttosto che blocchi. Questo risolve i problemi con ulteriori dichiarazioni goto e risolve anche un sacco di problemi con le variabili.

Per utilizzare goto:

echo foo 
if 1 == 1 goto bar 
echo quux 
goto nextbit 

:bar 
echo bar 
goto asdf 
:asdf 
echo baz 

:nextbit 
:: more script... 

o ad uso call:

echo foo 
if 1 == 1 (call :bar) else (call :quux) 
:: more script... 
exit /b 

:bar 
echo bar 
goto asdf 
:asdf 
echo baz 
exit /b 

:quux 
echo quux 
exit /b 
0

In questo caso si scopre di essere correlato ai poveri nidificazione e la struttura di un ciclo all'interno di un'istruzione IF, come chiaramente spiegato da https://stackoverflow.com/users/1012053/dbenham sopra.

Detto questo, ho capito un'altra considerazione simile a causa di questo problema ... prega di dare un'occhiata un il seguente problema e la successiva soluzione qui: ". was unexpected at this time" generated from batch script line 'if exist [file] (...

La soluzione era semplicemente il trattamento di '(' e ')' sulle linee ECHO all'interno di un blocco di istruzioni IF.

Il punto è, considerare la possibilità di trattare caratteri speciali come possibile causa di un problema durante la risoluzione di istruzioni IF (e possibilmente FOR).

HTH

Problemi correlati