Por que `echo -e“ \\\ SOME_TEXT ”` mostra apenas uma barra invertida?

19

Alguém poderia explicar o que está acontecendo nos bastidores na fuga de caracteres no shell do Linux? Eu tentei o seguinte e pesquisei bastante no Google, sem nenhum sucesso em entender o que (e como) está acontecendo:

root@sv01:~# echo -e "\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\\ Hello!"
\\\ Hello!
root@sv01:~# echo -e "\n Hello!"

 Hello!
root@sv01:~# echo -e "\\n Hello!"

 Hello!
root@sv01:~# echo -e "\\\n Hello!"
\n Hello!

Estou totalmente perdido lá, por exemplo, por que três barras invertidas dão apenas uma barra invertida? Eu esperaria: os dois primeiros serão escapados para um, o terceiro não encontrará nada para escapar, e assim permanecerá uma barra (linha no primeiro experimento), mas o que está acontecendo é que o terceiro simplesmente desaparece.
Por que estou recebendo uma barra invertida de quatro \\\\ Hello? Eu esperava que cada par desse uma barra invertida -> duas barras invertidas.

E por que preciso de três barras invertidas no último caso para escapar \ n? o que está acontecendo no fundo da fuga para conseguir isso? e como é diferente do \\ncaso?

Agradeço qualquer explicação do que está acontecendo nas linhas anteriores.

Mohammed Noureldin
fonte
echo -eo comportamento não é definido de qualquer maneira - consulte pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html . A saída é completamente definida pela implementação se houver uma barra invertida literal em qualquer lugar das entradas, e a única opção permitida é -n(o que significa que uma implementação compatível com os padrões terá echo -eimpressão -eem sua saída).
Charles Duffy
... mesmo se você tiver 100% de certeza de que seu shell é bash, mesmo assim echo -e não é seguro: echose comportará de acordo com o padrão se as opções de tempo de execução posixe xpg_echoestiverem ativadas ou se compiladas com opções de tempo de construção equivalentes. A prática segura é usar em printfvez disso - consulte as seções USO DO APLICATIVO e RACIONAL DO link acima, descrevendo como printfagir como um substituto echo.
Charles Duffy

Respostas:

28

Isto é porque bashe echo -ecombinado. A partir deman 1 bash

Uma barra invertida não citada ( \) é o caractere de escape. Ele preserva o valor literal do próximo caractere a seguir, com exceção de <newline>. [...]

Anexando caracteres entre aspas duplas preserva o valor literal de todos os caracteres entre as aspas, com exceção de $, `, \[...] A barra invertida mantém o seu significado especial somente quando seguido por um dos seguintes caracteres: $,`, ", \, ou <newline>.

O ponto é: a barra invertida entre aspas duplas nem sempre é especial.

Existem várias implementações de, echoem geral, é um embutido bash; o importante aqui é esse comportamento:

Se -eestiver em vigor, as seguintes seqüências são reconhecidas:
\\
barra invertida
[…]
\n
nova linha

Agora podemos decodificar:

  1. echo -e "\ Hello!"- nada de especial bash, nada de especial echo; \fica.
  2. echo -e "\\ Hello!"- o primeiro \diz bashtratar o segundo \literalmente; echofica \ Hello!e age como acima.
  3. echo -e "\\\ Hello!"- o primeiro \diz bashtratar o segundo \literalmente; echorecebe \\ Hello!e (por causa -e) reconhece \\como \.
  4. echo -e "\\\\ Hello!"- o primeiro \diz bashtratar o segundo \literalmente; o terceiro diz o mesmo sobre o quarto; echorecebe \\ Hello!e (por causa -e) reconhece \\como \.
  5. echo -e "\\\\\ Hello!"- o primeiro \diz bashtratar o segundo \literalmente; o terceiro diz o mesmo sobre o quarto; o último não é especial; echorecebe \\\ Hello!e (por causa -e) reconhece a inicial \\como \, a última \permanece intacta.

E assim por diante. Como você pode ver, até quatro barras invertidas consecutivas resultam em uma. É por isso que você precisa (pelo menos) nove deles para obter três. 9 = 4 + 4 + 1.

Agora com \n:

  1. echo -e "\n Hello!"- não há nada de especial bash, echo obtém a mesma string e (por causa -e) ele interpreta \ncomo uma nova linha.
  2. echo -e "\\n Hello!"- bashinterpreta \\como \; echoobtém \n Hello!e o resultado é o mesmo que acima.
  3. echo -e "\\\n Hello!"- bashinterpreta a inicial \\como \; echorecebe \\n Hello!e (por causa -e) ele interpreta \\como um literal \que precisa ser impresso.

Os resultados seriam diferentes com em 'vez de "(devido a bashcomportamento diferente ) ou sem -e( echocomportamento diferente ).

Kamil Maciorowski
fonte
11
Muito obrigado! Portanto, existem dois passos de escape, o passo feito pelo bash, e o segundo pelos -ejuízes, o texto já julgado pelo bash, certo? se estiver correto, isso remove a confusão. Você poderia mencionar como se sedcomporta? ele tem sua própria construção na técnica de escape? então eu quero dizer se comporta como eco -e?
Mohammed Noureldin
2
@MohammedNoureldin Sim, existem duas etapas. Sua pergunta original está correta, não vamos complicar demais sed. Você pode fazer outra pergunta ( sedapenas sobre ), basta fazer sua própria pesquisa primeiro.
Kamil Maciorowski
3
O @MohammedNoureldin sedseguirá os mesmos princípios básicos: o bash interpretará a linha de comando de acordo com suas regras, analisando (e talvez removendo) aspas e escapes. O resultado disso é passado para sed, que o interpreta de acordo com suas regras de escape. BTW, você pode simplificar isso usando uma string de aspas simples bash, uma vez que não possui uma interpretação de escape de eny (por bash) - o bash remove as aspas simples e passa o que está dentro delas diretamente para o comando.
Gordon Davisson
Eu ainda tenho um pequeno problema no echo -e "\\\n Hello!"caso. Aqui o bash escapará , e se tornará \\n, depois -eescapará as duas barras invertidas resultantes \\ne depois se tornarão \n. agora quem interpreta \npara torná-lo nova linha? Normalmente, no caso de echo -e "\n Hello!", o bash não faz nada e -einterpreta \ncomo nova linha. mas, na primeira situação mencionada, o processo de interpretação foi realizado antes \nde ser interpretado. Você poderia explicar isso, por favor?
Mohammed Noureldin 13/09/17
11
Ok, minha culpa, eu tenho lido sobre isso por 2 dias com suas noites, portanto, aparentemente, comecei a misturar os casos, acredito que tenho outra coisa sedque me confundiu ontem à noite (talvez eu tenha feito algo errado ontem), mas agora eu tentei novamente o mesmo com echo -ee sed, e recebi a mesma coisa que exceto, obrigado!
Mohammed Noureldin 13/09