Come posso dividere un comando shell su più righe quando utilizzo un'istruzione IF?


385

Come posso dividere un comando su più righe nella shell, quando il comando fa parte di ifun'istruzione?

Questo funziona:

if ! fab --fabfile=.deploy/fabfile.py --forward-agent --disable-known-hosts deploy:$target; then rc=1                                                                       
fi

Questo non funziona:

# does not work:
if ! fab --fabfile=.deploy/fabfile.py \ 
  --forward-agent \
  --disable-known-hosts deploy:$target; then   
  rc=1
fi

Invece dell'intero comando in esecuzione, ottengo:

./script.sh: line 73: --forward-agent: command not found

Ancora più importante, cosa manca alla mia comprensione di Bash che mi aiuterà a capire questo e problemi simili in futuro?


2
Qual è l'errore? Sono in grado di eseguire $ if ! cp -n log/server1.log \ > .; then echo no copy; fisenza errori, con una nuova riga dopo\
Miserable Variable

15
Hai spazi dopo le barre rovesciate del terminale \ ? Sono piuttosto difficili da vedere. Se lo fai, potresti voler vedere se puoi rendere il tuo editor rimuovere gli spazi finali o renderli più visibili.
msw,

10
Sì, erano gli spazi dopo le barre rovesciate del terminale. Totalmente. Grazie.
Dmitry Minkovsky,

E sì, scusami, avrei dovuto postare "l'errore" (risultato inatteso)! Colpa mia! Modifica ora.
Dmitry Minkovsky,

Qual è stata la tua comprensione? Non fa nemmeno parte della domanda.
Hakre,

Risposte:


567

La continuazione della linea fallirà se si hanno spazi bianchi (spazi o caratteri di tabulazione) dopo la barra rovesciata e prima della nuova riga. Senza tale spazio bianco, il tuo esempio funziona bene per me:

$ cat test.sh
if ! fab --fabfile=.deploy/fabfile.py \
   --forward-agent \
   --disable-known-hosts deploy:$target; then
     echo failed
else
     echo succeeded
fi

$ alias fab=true; . ./test.sh
succeeded
$ alias fab=false; . ./test.sh
failed

Alcuni dettagli sono stati promossi dai commenti: il backslash di continuazione della riga nella shell non è un caso speciale; è semplicemente un'istanza della regola generale che una barra rovesciata "cita" il carattere immediatamente successivo, impedendo qualsiasi trattamento speciale al quale sarebbe normalmente soggetto. In questo caso, il personaggio successivo è una nuova riga e il trattamento speciale che viene impedito sta terminando il comando. Normalmente, un personaggio citato finisce incluso letteralmente nel comando; una nuova riga rovesciata viene invece eliminata del tutto. Altrimenti, il meccanismo è lo stesso. E la barra rovesciata cita solo il carattere immediatamente successivo; se quel personaggio è uno spazio o una scheda, ottieni solo uno spazio o una scheda tra virgolette e ogni nuova riga successiva non viene quotata.


5
Mark, sai, dovevo avere spazi bianchi. Sono in grado di riprodurre l'errore solo quando si aggiungono spazi bianchi dopo `s. For example, when adding one after the first `, ottengo ./soundops: line 73: --forward-agent: command not found. Il mio problema era che non avevo capito questo errore. Perché avere uno spazio bianco provoca quell'errore? Lo spazio bianco + \n"nega" il `` e delimita un comando?
Dmitry Minkovsky,

84
Una barra rovesciata davanti alla newline impedisce alla newline di terminare il comando. Ma proprio come le sequenze di escape speciali come "\ n" funzionano solo con nulla tra la barra rovesciata e la n, la barra rovesciata-newline funziona solo con nulla tra la barra rovesciata e la newline.
Mark Reed,

19
Hahaha wow, ovviamente ha senso. Non l'ho mai visto così. Sbalorditivo, eppure così semplice: è solo una newline fuggita. Odio i personaggi invisibili. Avrebbero molto più senso per me se fossero tutti visibili. Grazie!
Dmitry Minkovsky,

7
Nella maggior parte degli editor puoi rendere visibili quei personaggi invisibili.
lucasvc,

1
La barra rovesciata e la nuova riga vengono eliminate dalla riga di comando effettiva, ma viene conservato qualsiasi spazio bianco iniziale nella riga successiva. Quindi, se si tratta di un problema o meno dipende dal fatto che gli spazi bianchi siano un problema in quel punto nel comando a riga singola.
Mark Reed,

52

Per utenti Windows / WSL / Cygwin ecc:

Assicurati che le terminazioni di riga siano feed di riga Unix standard, ovvero solo \n(LF).

L'uso delle terminazioni di riga \r\n(CRLF) di Windows interromperà l'interruzione di riga di comando.


Questo perché \la fine di una riga con la fine della riga di Windows si traduce in \ \r \n.
Come Mark spiega correttamente sopra:

La continuazione della linea fallirà se si dispone di spazi bianchi dopo la barra rovesciata e prima della nuova riga.

Ciò include non solo lo spazio ( ) o le schede ( \t) ma anche il ritorno a capo ( \r).


1
Questo risolve il problema creato quando si creava uno script in Windows e poi lo si utilizza in Windows bash (ad esempio bash -c MyShellScript.sh dove MyShellScript.sh è stato creato nell'editor di Windows). Devi salvare MyShellScript.sh in formato UNIX magari usando Notepad ++.
BSalita,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.