Comment puis-je diviser une commande shell sur plusieurs lignes lors de l'utilisation d'une instruction IF?

386

Comment puis-je diviser une commande sur plusieurs lignes dans le shell, lorsque la commande fait partie d'un if instruction?

Cela marche:

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

Cela ne fonctionne pas:

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

Au lieu d'exécuter toute la commande, j'obtiens:

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

Plus important encore, qu'est-ce qui manque à ma compréhension de Bash qui m'aidera à comprendre ce problème et des problèmes similaires à l'avenir?

Dmitry Minkovsky
la source
2
Quelle est l'erreur? Je peux exécuter $ if ! cp -n log/server1.log \ > .; then echo no copy; fisans erreur, avec une nouvelle ligne après\
Miserable Variable
16
Avez-vous des espaces après les barres obliques inverses du terminal \ ? Ils sont assez difficiles à voir. Si vous le faites, vous voudrez peut-être voir si vous pouvez faire en sorte que votre éditeur supprime les espaces de fin ou les rende plus visibles.
msw
10
Oui, il s'agissait d'espaces après les contre-obliques du terminal. Totalement. Je vous remercie.
Dmitry Minkovsky
Et oui, désolé, j'aurais dû poster "l'erreur" (résultat inattendu)! Ma faute! Modification maintenant.
Dmitry Minkovsky
Quelle était votre compréhension? Cela ne fait pas partie de la question non plus.
hakre

Réponses:

569

La suite de ligne échouera si vous avez des espaces (espaces ou tabulations) après la barre oblique inverse et avant la nouvelle ligne. Sans un tel espace, votre exemple fonctionne bien pour moi:

$ 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

Quelques détails promus dans les commentaires: la barre oblique inverse de continuation de ligne dans le shell n'est pas vraiment un cas spécial; c'est simplement un exemple de la règle générale selon laquelle une barre oblique inverse "cite" le caractère immédiatement suivant, empêchant tout traitement spécial auquel elle serait normalement soumise. Dans ce cas, le caractère suivant est une nouvelle ligne et le traitement spécial empêché met fin à la commande. Normalement, un caractère cité se retrouve inclus littéralement dans la commande; un retour à la ligne annulé est à la place entièrement supprimé. Mais sinon, le mécanisme est le même. Et la barre oblique inverse ne cite que le caractère immédiatement suivant; si ce caractère est un espace ou une tabulation, vous obtenez simplement un espace ou une tabulation entre guillemets, et toute nouvelle ligne subséquente reste sans guillemets.

Mark Reed
la source
5
Mark, tu sais, j'ai dû avoir des espaces blancs. Je ne peux reproduire l'erreur que lors de l'ajout d'espaces après le `s. For example, when adding one after the first `, j'obtiens ./soundops: line 73: --forward-agent: command not found. Mon problème était que je ne comprenais pas cette erreur. Pourquoi avoir un espace blanc entraîne-t-il cette erreur? Le blanc + \n"annule" le `` et délimite une commande?
Dmitry Minkovsky
84
Une barre oblique inverse devant la nouvelle ligne empêche la nouvelle ligne de terminer la commande. Mais tout comme les séquences d'échappement spéciales comme "\ n" ne fonctionnent qu'avec rien entre la barre oblique inverse et le n, la barre oblique inversée ne fonctionne qu'avec rien entre la barre oblique inverse et la nouvelle ligne.
Mark Reed
19
Hahaha wow, bien sûr, cela a du sens. Je ne l'ai jamais vu de cette façon. Une révélation, pourtant si simple: c'est juste une nouvelle ligne échappée. Je déteste les personnages invisibles. Ils auraient tellement plus de sens pour moi s'ils étaient tous visibles. Je vous remercie!
Dmitry Minkovsky
7
Dans la plupart des éditeurs, vous pouvez rendre visibles ces caractères invisibles.
lucasvc
1
La barre oblique inverse et la nouvelle ligne sont supprimées de la ligne de commande effective, mais tout espace blanc de tête sur la ligne suivante est conservé. Donc, que ce soit un problème ou non, cela dépend si les espaces blancs seraient un problème à ce stade de la commande sur une seule ligne.
Mark Reed
52

Pour les utilisateurs de Windows / WSL / Cygwin, etc.:

Assurez-vous que vos fins de ligne sont des sauts de ligne Unix standard, c'est-à-dire \n(LF) uniquement.

L'utilisation de fins de ligne Windows \r\n(CRLF) interrompra la rupture de la ligne de commande.


En effet, avoir \à la fin d'une ligne avec une fin de ligne Windows se traduit par \ \r \n.
Comme Mark l'explique correctement ci-dessus:

La continuation de ligne échouera si vous avez des espaces après la barre oblique inverse et avant la nouvelle ligne.

Cela inclut non seulement l'espace ( ) ou les tabulations ( \t) mais également le retour chariot ( \r).

Czechnology
la source
1
Cela corrige le problème créé lors de la création d'un script dans Windows, puis de son utilisation dans Windows bash (par exemple bash -c MyShellScript.sh où MyShellScript.sh a été créé dans l'éditeur Windows). Vous devez enregistrer MyShellScript.sh au format UNIX en utilisant peut-être notepad ++.
BSalita