2016-06-16 25 views
9

Ho questo semplice script di prova:Perché gli spazi vengono inseriti in questo file batch in fase di runtime?

echo start 
falsey^
&& echo nope 
echo end 

falsey è un piccolo programma C che ho fatto per aiutare prova, restituisce semplicemente 1:

int main(int argc, const char** argv) { 
     return 1; 
} 

Il problema è che quando apro cmd ed esegui questo script batch, inserisce un paio di spazi tra i due & s, il che provoca in modo errato echo nope:

C:\jenkins-foo-test>foo.bat 
C:\jenkins-foo-test>echo start 
start 
C:\jenkins-foo-test>falsey & & echo nope 
nope 
C:\jenkins-foo-test>echo end 
end 

ho capito un paio di soluzioni per questo, come ad esempio citazioni mettendo tutto il &&:

falsey^
"&&" echo nope 

Citazioni in realtà non funzionano in questo caso, vedere @dbenham's answer per il motivo.

cadere il ^ e la fusione delle due linee:

falsey && echo nope 

o l'aggiunta di uno spazio davanti alla &&:

falsey^
&& echo nope 

Ciascuna di queste tre opzioni correttamente non vengono stampati nope. Ma tutti hanno ancora spazi extra quando cmd.exe stampa i comandi in esecuzione.

Quindi, perché vengono inseriti questi spazi aggiuntivi e come posso interrompere cmd.exe dal rompere le cose senza dover contortare il mio codice in forme leggermente innaturali tutto il tempo?

+2

Qual è il vantaggio di sfuggire un'interruzione di riga e di mettere '&&' nella riga successiva, comunque? 'falsey && echo nope' o' falsey && (\ n echo nope \ n) '(dove' \ n' sono nuove linee) è una convenzione standard. Quello che stai facendo è come iniziare una frase con una congiunzione. Ed è imbarazzante. – rojo

+0

Quale editor di testo stai usando per modificare il tuo file batch? –

+0

@rojo Perché le linee che in realtà voglio usare per questo sono piuttosto lunghe. Mettere il '&&' all'inizio della riga successiva rende chiaro che l'esecuzione dipende da quella della riga precedente. – 8bittree

risposta

8

The line continuation ^ escapes the first character on the next line, quindi il primo & viene trattato come un valore letterale e viene passato come argomento a falsey. Il secondo & viene considerato come una semplice concatenazione di comandi.

Una soluzione semplice per ottenere && di essere trattato come comando condizionale concatenazione è quello di mettere il && sulla linea prima:

falsey &&^ 
echo nope 

oppure si potrebbe mettere uno spazio prima del &&

falsey^
&& echo nope 

L'altra opzione è usare il trucco di reindirizzamento che jeb indica nella sua risposta collegata, ma non uso mai quel trucco.


quanto riguarda la tua "soluzione" con citato "&&" - si sta prendendo in giro da soli. Sembra funzionare quando il falso fallisce.Ma se il vostro comando ha esito positivo, allora si hanno problemi:

echo ONE^
"&&" echo TWO 

- USCITA -

C:\test>echo ONE " && " echo TWO 
ONE " 
'" echo TWO' is not recognized as an internal or external command, 
operable program or batch file. 

Nota che i && opere perché la prima " è sfuggito, in modo che il && non è citato. Se si aggiunge uno spazio prima del "&&"

echo ONE^ 
"&&" echo TWO 

poi si ottiene la seguente

C:\test>echo ONE "&&" echo TWO 
ONE "&&" echo TWO 

perché ora lo spazio è sfuggito ed il "&&" è citato.


quanto riguarda il tuo commento, è possibile ignorare quegli spazi extra - sono un artefatto di come il parser visualizza la linea quando ECHO è ON. Il parser spesso riorganizza la linea in modo significativo, ma normalmente non influisce sul risultato.

Per esempio

< nul set test=OK 
echo [%test%] 

--OUTPUT--

C:\test>set test=OK 0<nul 

C:\test>echo [OK] 
[OK] 

Nota come la linea SET fece eco è completamente risistemato. Il reindirizzamento viene compresso e spostato alla fine dell'istruzione, con uno spazio prima del reindirizzamento. Potresti pensare che lo spazio sia incluso nel compito, ma puoi vedere che non lo è :-)

L'unica volta che potresti doverti preoccupare del riarrangiamento è se il comando viene usato in una pipe.

Ad esempio:

(set test=OK&call echo [%%^^test%%])|findstr "^" 

--OUTPUT--

C:\test>(set test=OK & call echo [%^test%]) | findstr "^" 
[OK ] 

Si può vedere che c'è un singolo spazio extra indesiderato che viene incluso nel valore SET. Questo è un artefatto del modo in cui le pipe vengono implementate: ogni lato viene eseguito in un nuovo processo CMD.EXE e la riga viene analizzata più volte. Puoi vedere da dove viene lo spazio usando %CMDCMDLINE% per visualizzare la riga di comando passata al cmd.exe sul lato sinistro.

(set test=OK&call echo [%%^^test%%] %%^^cmdcmdline%%)|findstr "^" 

--OUTPUT--

C:\test>(set test=OK & call echo [%^test%] %^cmdcmdline%) | findstr "^" 
[OK ] C:\WINDOWS\system32\cmd.exe /S /D /c" (set test=OK & call echo [%^test%] %^cmdcmdline%)" 

Vedi Why does delayed expansion fail when inside a piped block of code? per ulteriori informazioni su molti capricci con tubi. In particolare, prestare attenzione alla risposta selezionata per una buona spiegazione di ciò che sta accadendo.

+0

Che dire degli spazi extra quando non c'è '^' e tutto è una riga? – 8bittree

+0

@ 8 bittree - Questi spazi extra appaiono solo nell'output quando il comando viene echeggiato (ECHO è ON). Sono un artefatto del parser. Gli spazi non vengono effettivamente passati al comando, quindi non hanno alcun impatto. L'unica volta che hanno un impatto è quando il comando viene analizzato più volte ed eseguito in un nuovo processo cmd.exe, come quando viene usato in una pipe. – dbenham

+0

@ 8bittree - Guarda la mia ultima modifica per una migliore spiegazione degli "spazi extra", e perché normalmente puoi ignorarli. – dbenham

Problemi correlati