Pourquoi les commandes «echo -e» ne semblent-elles pas produire la bonne sortie?

21

Dans le terminal d'Ubuntu 18.04 LTS, lorsque j'écris cette commande:

echo -e "Hello\\\n"

Il donne ceci en sortie:

Hello\n

Mais il devrait s'imprimer, comme le dit la page de manuel :

Hello\

Autrement dit, imprimez d'abord Hello, puis \, un caractère de nouvelle ligne (puis une autre nouvelle ligne). Où est le problème?

Voir ces quelques echo -ecommandes et leur sortie :

man420@man420-X542UQ:~$ echo -e "HEllo\a\a\a\a\a\a\\\n"
HEllo\n
man420@man420-X542UQ:~$ echo -e "HEllo\\\n"
HEllo\n
man420@man420-X542UQ:~$ echo -e "HEllo\a\\\n"
HEllo\n
yolin00
la source
yes.for first 2 \ it should output a \ .and last \ and n make a backslash escape \ n (new line) .so why it should print Hello \
yolin00
1
Essayez-le sans les guillemets.
ajgringo619
2
Eliah Kagan a fourni une réponse étonnante, que vous devriez accepter.
vanadium
2
Ne pas utiliser echoen premier lieu: utiliser printf.
chepner
2
Utilisez toujours des guillemets simples si vous voulez être sûr que ce que vous écrivez est précisément ce qui est passé à la commande comme argument.
Giacomo Alzetta

Réponses:

29

Les barres obliques inverses sont traitées spécialement par echo -e, mais d'abord elles sont parfois traitées spécialement par le shell (qui dans ce cas est bash), selon les règles de citation du shell .

L'argument echovoit réellement est Hello\\n. Parce que vous êtes passé -eà echo, il traite les échappements antislash spécialement et \\est réduit à un seul \. La finale nn'est pas échappée, elle apparaît donc littéralement.

La raison en est que, avant et indépendamment de son fonctionnement echo, le shell traite \spécialement dans certains contextes mais pas dans d'autres. Les \caractères entre guillemets sont toujours traités spécialement, les guillemets simples \ ne sont jamais traités spécialement, mais le traitement des caractères entre guillemets \ , comme dans la commande que vous avez exécutée, est plus subtil et compliqué.

Lorsque le shell rencontre du texte entre guillemets doubles dans une commande, comme avec "Hello\\\n", il traite \comme un caractère d'échappement lorsqu'il précède un caractère qui peut lui-même avoir une signification particulière à l'intérieur des guillemets doubles et pas autrement .

  1. Parce que \parfois a une signification particulière à l'intérieur "", un \qui précède immédiatement un autre \a pour effet de citer cette seconde \. Donc, à l'intérieur des guillemets doubles, les premiers \\sont regroupés \.
  2. Après ces deux premiers \caractères, il y a un troisième \caractère qui n'est pas affecté par ces deux premiers et qui précède un n. Mais ce nn'est pas un personnage qui est jamais traité spécialement à l'intérieur de guillemets doubles, donc \avant il n'est pas traité spécialement dans cette situation. \nReste ainsi \n.

L'effet est que, entre guillemets, \\\nest interprété comme \\n.

Quand echo -evoit \\n, le premier \supprime la signification spéciale du second, echoimprime donc \nlittéralement pour ce texte.


Si votre objectif est d'imprimer Helloavec une nouvelle ligne supplémentaire mais sans barre oblique inverse (la question était à l'origine ambiguë à ce sujet, et je pense que c'est un exemple utile), alors une solution consiste à supprimer a \. Exécution des echo -e "Hello\\n"sorties Helloavec une nouvelle ligne supplémentaire à la fin.

Une meilleure solution consiste à utiliser des guillemets simples et à écrire echo -e 'Hello\n'. Les guillemets simples sont la forme de devis la plus puissante. Une solution encore meilleure consiste généralement à utiliser à la printfplace de echo, ce qui serait le cas dans ce cas printf 'Hello\n\n'.

Si votre objectif est d'imprimer, Hello\y compris la barre oblique inverse, suivie d'une nouvelle ligne supplémentaire , l'approche à guillemets doubles est possible mais lourde. Pour le comprendre, travaillez en arrière: echo -econvertit \\en \et \nvers une nouvelle ligne, et les guillemets doubles convertis \\en \, vous pouvez donc le faire avec six barres obliques inverses ( echo -e "Hello\\\\\\n"), car \\nse transforme en \nune barre oblique inversée en échappant une autre. Vous pouvez également le faire avec cinq, car les guillemets doubles sont conservés \nlorsque le \n'est pas échappé.

Cela illustre les avantages des guillemets simples: mettez simplement ce que vous voulez echo -evoir à l'intérieur des guillemets simples ( echo -e 'Hello\\\n'). printfest également bon ici. Une option est printf 'Hello\\\n\n'. Mais ce printfqui brille vraiment, c'est que vous pouvez ajouter des arguments supplémentaires. Vous pouvez utiliser printf '%s\n\n' 'Hello\', qui insère le deuxième argument (littéralement Hello\parce que les guillemets simples ne changent rien) à la place de %s.

Eliah Kagan
la source