Como posso dividir um comando shell em várias linhas ao usar uma instrução SE?

385

Como posso dividir um comando em várias linhas no shell, quando o comando faz parte de uma ifinstrução?

Isso funciona:

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

Isso não funciona:

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

Em vez de todo o comando em execução, recebo:

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

Mais importante, o que está faltando no meu entendimento do Bash que me ajudará a entender esse e outros problemas semelhantes no futuro?

Dmitry Minkovsky
fonte
2
Qual é o erro? Eu sou capaz de executar $ if ! cp -n log/server1.log \ > .; then echo no copy; fisem erro, com uma nova linha após\
Miserable Variable
15
Você tem espaços após as barras invertidas do terminal \ ? Eles são bem difíceis de ver. Se o fizer, convém verificar se é possível fazer com que seu editor remova os espaços à direita ou os torne mais visíveis.
RSU
10
Sim, foram espaços após as barras invertidas do terminal. Totalmente. Obrigado.
Dmitry Minkovsky
E sim, desculpe, eu deveria ter postado o "erro" (resultado inesperado)! Foi mal! Editando agora.
Dmitry Minkovsky
Qual foi o seu entendimento? Também não faz parte da questão.
22414 ha hakre

Respostas:

567

A continuação da linha falhará se você tiver espaços em branco (espaços ou caracteres de tabulação) após a barra invertida e antes da nova linha. Sem esse espaço em branco, seu exemplo funciona bem para mim:

$ 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

Alguns detalhes promovidos a partir dos comentários: a barra invertida de continuação de linha no shell não é realmente um caso especial; é simplesmente uma instância da regra geral em que uma barra invertida "cita" o caractere imediatamente seguinte, impedindo qualquer tratamento especial ao qual normalmente estaria sujeito. Nesse caso, o próximo caractere é uma nova linha e o tratamento especial que está sendo impedido está encerrando o comando. Normalmente, um personagem citado acaba literalmente incluído no comando; uma nova linha com barra invertida é totalmente excluída. Mas, caso contrário, o mecanismo é o mesmo. E a barra invertida cita apenas o caractere imediatamente seguinte; se esse caractere for um espaço ou tab, você receberá um espaço ou tab entre aspas e qualquer nova linha subsequente permanecerá entre aspas.

Mark Reed
fonte
5
Mark, você sabe, eu devo ter tido espaços em branco. Eu sou capaz de reproduzir o erro apenas ao adicionar espaços em branco após o `s. For example, when adding one after the first `, eu recebo ./soundops: line 73: --forward-agent: command not found. Meu problema foi que não entendi esse erro. Por que ter um espaço em branco resulta nesse erro? O espaço em branco + \n"nega" o `` e delimita um comando?
Dmitry Minkovsky
84
Uma barra invertida na frente da nova linha impede que a nova linha termine o comando. Mas assim como seqüências de escape especiais como "\ n" só funcionam com nada entre a barra invertida e a n, barra invertida-nova linha só funcionam com nada entre a barra invertida e a nova linha.
Re
19
Hahaha uau, é claro que faz sentido. Nunca vi dessa maneira. Surpreendente, mas tão simples: é apenas uma nova linha que escapou. Eu odeio personagens invisíveis. Eles fariam muito mais sentido para mim se fossem todos apenas visíveis. Obrigado!
Dmitry Minkovsky
7
Na maioria dos editores, você pode tornar visíveis esses caracteres invisíveis.
Lucasvc
11
A barra invertida e a nova linha são excluídas da linha de comando efetiva, mas qualquer espaço em branco à esquerda na próxima linha é preservado. Portanto, se é um problema ou não, depende se o espaço em branco seria um problema nesse ponto do comando de linha única.
Re
52

Para usuários de Windows / WSL / Cygwin etc:

Certifique-se de que as terminações de sua linha sejam feeds de linha Unix padrão, ou seja, \napenas (LF).

O uso de terminações de linha do Windows \r\n(CRLF) interromperá a quebra de linha de comando.


Isso ocorre porque \, ao final de uma linha com final de linha do Windows, é traduzido como \ \r \n.
Como Mark explica corretamente acima:

A continuação da linha falhará se você tiver um espaço em branco após a barra invertida e antes da nova linha.

Isso inclui não apenas espaço ( ) ou tabulações ( \t), mas também o retorno de carro ( \r).

Czechnology
fonte
11
Isso corrige o problema criado ao criar um script no Windows e depois usá-lo no Windows bash (por exemplo, bash -c MyShellScript.sh onde MyShellScript.sh foi criado no editor do Windows). Você precisa salvar o MyShellScript.sh no formato UNIX, talvez usando o bloco de notas ++.
BSalita