Por que os comandos "eco-e" não parecem produzir a saída correta?

21

No terminal do Ubuntu 18.04 LTS, quando escrevo este comando:

echo -e "Hello\\\n"

Dá isto como a saída:

Hello\n

Mas deve ser impresso, como diz a página do manual :

Hello\

Ou seja, primeiro imprima Hello, depois \um caractere de nova linha (e depois outra nova linha). Onde está o problema?

Veja estes poucos echo -ecomandos e sua saída :

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
fonte
yes.for primeiro 2 \ ele deve produzir um \ .e último \ e n fazer uma fuga de barra invertida \ n (nova linha) .so porque deve imprimir Hello \
yolin00
11
Experimente sem as aspas.
ajgringo619
2
Uma resposta surpreendente foi dada por Eliah Kagan, que você deve aceitar.
vanadium
2
Não use echoem primeiro lugar: use printf.
chepner 01/09
2
Sempre use aspas simples se quiser ter certeza de que o que você escreve é ​​exatamente o que é passado ao comando como argumento.
Giacomo Alzetta

Respostas:

29

As barras invertidas são tratadas especialmente por echo -e, mas primeiro são às vezes tratadas especialmente pelo shell (que neste caso é bash), de acordo com as regras de cotação do shell .

O argumento echorealmente vê é Hello\\n. Como você passou -epara echo, ele trata escapes de barra invertida especialmente e \\é recolhido para um único \. A final nnão é escapada, então aparece literalmente.

A razão para isso é que, antes e separadamente da operação em echosi, o shell trata \especialmente em alguns contextos, mas não em outros. Não cotadas \personagens são sempre tratados de maneira especial, único citado \ nunca são tratados de maneira especial, mas o tratamento da dupla citou \ personagens, como no comando que você executou, é mais sutil e complicado.

Quando o shell encontra um texto com aspas duplas em um comando, "Hello\\\n"ele trata \como um caractere de escape quando precede um caractere que pode ter um significado especial entre aspas duplas e não o contrário .

  1. Porque \às vezes tem um significado especial por dentro "", um \que precede imediatamente outro \tem o efeito de citar esse segundo \. Assim, entre aspas duplas, as primeiras \\são recolhidas \.
  2. Após esses dois primeiros \caracteres, existe um terceiro \caractere que não é afetado pelos dois primeiros e que precede um n. Mas nnão é um personagem que é tratado especialmente entre aspas duplas, portanto, o \antes não é tratado especialmente nessa situação. Assim \nfica \n.

O efeito é que, entre aspas duplas, \\\né interpretado como \\n.

Quando echo -e\\n, o primeiro \remove um significado especial do segundo, então echoimprime \nliteralmente para esse texto.


Se seu objetivo é imprimir Hellocom uma nova linha extra, mas sem barras invertidas (a pergunta era originalmente ambígua sobre isso, mais acho que é um exemplo útil), então uma solução é remover a \. Execução de echo -e "Hello\\n"saídas Hellocom uma nova linha extra no final.

Uma solução melhor é usar aspas simples e escrever echo -e 'Hello\n'. Aspas simples são a forma mais forte de citar. Uma solução ainda melhor é geralmente usar em printfvez de echo, o que nesse caso seria printf 'Hello\n\n'.

Se seu objetivo é imprimir, Hello\incluindo a barra invertida, seguida por uma nova linha extra , a abordagem de aspas duplas é possível, mas complicada. Para descobrir, trabalhe de trás para frente: echo -econverte \\para \e \npara uma nova linha e aspas duplas \\para \, para que você possa fazer isso com seis barras invertidas ( echo -e "Hello\\\\\\n"), porque \\nse transforma \ndevido a uma barra invertida escapando da outra. Você também pode fazer isso com cinco, porque as aspas duplas ficam retidas \nquando \não é escapado.

Isso ilustra o benefício da citação simples: basta colocar o que você deseja echo -ever dentro das aspas simples ( echo -e 'Hello\\\n'). printftambém é bom aqui. Uma opção é printf 'Hello\\\n\n'. Mas onde printfrealmente brilha é que você pode conectar argumentos adicionais. Você pode usar printf '%s\n\n' 'Hello\', que insere o segundo argumento (literalmente, Hello\porque aspas simples não mudam nada) no lugar de %s.

Eliah Kagan
fonte