Questo è il comportamento previsto perché %1
viene espanso quando viene analizzata la riga e l'intero costrutto IF parentesi viene analizzato tutto in un unico passaggio. Quindi non è possibile visualizzare il risultato dello SHIFT fino a quando non viene analizzata una nuova riga, che non si verificherà fino a quando non si è lasciato il blocco tra parentesi.
Lo stesso problema si verifica quando si espande una variabile di ambiente utilizzando %var%
. Con le variabili di ambiente è possibile aggirare il problema abilitando l'espansione ritardata utilizzando SETLOCAL EnableDelayedExpansion
e quindi utilizzando !var!
. Ma non esiste un modo analogo per espandere i parametri usando l'espansione ritardata.
EDIT 2013-06-21 - Non c'è un modo simile, ma esiste un modo semplice relativamente lento.
È possibile forzare la ripetizione della linea utilizzando CALL e il raddoppio dello %
.
@echo off
if "%1"=="/p" (
echo %1
shift
echo "shifted"
call echo %%1
)
EDIT 2016/07/15 Il code in Vladislav's answer è una cattiva pratica, in quanto implica che si può tornare indietro all'interno di un blocco di codice dopo che hai utilizzato GOTO di lasciarlo. Questo semplicemente non funziona. GOTO uccide immediatamente tutti i blocchi di codice analizzati. Si potrebbe anche avere scritto il codice di Vladislav come:
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
)
Se la condizione è falsa, allora l'intero blocco viene saltato. Se la condizione è TRUE, GOTO uccide immediatamente il blocco, quindi l'esecuzione viene eseguita normalmente su: true label (nessun contesto di blocco). L'extra )
alla fine viene semplicemente ignorato.
Nota che non è possibile aggiungere un ELSE con questo costrutto. Quanto segue non dà il risultato desiderato:
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
) else (
echo This will execute regardless whether arg1 is /p or not
)
Se FALSE, viene eseguito solo il blocco ELSE. se TRUE, quindi il blocco superiore viene eseguito e immediatamente ucciso. Il resto del codice viene eseguito e la riga ) else (
viene ignorata perché le funzioni )
come REM se il parser si aspetta un comando e non ci sono blocchi parentesi attivi nello stack.
Consiglio vivamente di non gettare mai un'etichetta all'interno di un blocco di codice in parentesi come mostrato sopra (o come ha fatto Vladislav).
Qui di seguito è un modo migliore (più semplice e non fuorvianti) per fare la stessa cosa:
@echo off
if not "%1"=="/p" goto :skip
echo "%1"
shift
echo shifted
echo "%1"
:skip
Si potrebbe sostenere un/THEN/concetto ELSE IF con alcune etichette extra e GOTO
@echo off
if not "%1"=="/p" goto :notP
echo "%1"
shift
echo shifted
echo "%1"
goto :endIf
:notP
echo not /p
:endIf
Ho finito per trovare la risposta qui: [Maiusc non funziona nello script batch] (http://social.technet.microsoft.com/Forums/scriptcenter/en-US/7bbbe8df-e3c0-46ab-aede-396c2b6f6184/shift-doesnt-work-in-batch-script) – piebie