¿Por qué los comandos "echo -e" no parecen producir la salida correcta?

21

En el terminal de Ubuntu 18.04 LTS, cuando escribo este comando:

echo -e "Hello\\\n"

Da esto como la salida:

Hello\n

Pero debería imprimirse, como dice la página del manual :

Hello\

Es decir, primero imprimir Hello, luego \, luego un carácter de nueva línea (y luego otra nueva línea). ¿Dónde está el problema?

Vea estos pocos echo -ecomandos y su salida :

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
fuente
sí. para los primeros 2 \ debería mostrar un \ .y último \ yn hacer una barra invertida escape \ n (nueva línea). Entonces, ¿por qué debería imprimir Hello \
yolin00 el
1
Pruébalo sin las comillas.
ajgringo619
2
Eliah Kagan proporcionó una respuesta sorprendente, que debe aceptar.
vanadio
2
No usar echoen primer lugar: usar printf.
chepner
2
Utilice siempre comillas simples si desea asegurarse de que lo que escribe es precisamente lo que se pasa al comando como argumento.
Giacomo Alzetta

Respuestas:

29

Las barras invertidas son tratadas especialmente por echo -e, pero primero a veces son tratadas especialmente por el shell (que en este caso es bash), de acuerdo con las reglas de cotización del shell .

El argumento echorealmente ve es Hello\\n. Debido a que ha pasado -ea echo, trata especialmente los escapes de barra invertida y \\se contrae en uno solo \. La final nno se escapa, por lo que aparece literalmente.

La razón de esto es que, antes y por separado de la operación de echosí mismo, el shell trata \especialmente en algunos contextos pero no en otros. Los \caracteres sin comillas siempre se tratan especialmente, las comillas simples \ nunca se tratan especialmente, pero el tratamiento de los \ caracteres con comillas dobles , como en el comando que ejecutó, es más sutil y complicado.

Cuando el shell encuentra texto entre comillas dobles en un comando, como con "Hello\\\n", trata \como un carácter de escape cuando precede a un carácter que puede tener un significado especial dentro de comillas dobles y no de otra manera .

  1. Debido a que a \veces tiene un significado especial en el interior "", un \que precede inmediatamente a otro \tiene el efecto de citar ese segundo \. Entonces, dentro de las comillas dobles, las primeras \\se contraen \.
  2. Después de esos dos primeros \caracteres, hay un tercer \personaje que no se ve afectado por esos dos primeros y que precede a un n. Pero nno es un personaje que alguna vez se trata especialmente entre comillas dobles, por lo que \antes no se trata especialmente en esta situación. Así se \nqueda \n.

El efecto es que, entre comillas dobles, \\\nse interpreta como \\n.

Cuando echo -eve \\n, el primero \elimina el significado especial del segundo, por lo que echoimprime \nliteralmente para ese texto.


Si su objetivo es imprimir Hellocon una nueva línea adicional pero sin barras invertidas (la pregunta era originalmente ambigua sobre esto, además creo que es un ejemplo útil), entonces una solución es eliminar a \. Ejecución de echo -e "Hello\\n"salidas Hellocon una nueva línea adicional al final.

Una mejor solución es usar comillas simples y escribir echo -e 'Hello\n'. Las comillas simples son la forma más fuerte de citar. Por lo general, una solución aún mejor es usar en printflugar de echo, lo que en este caso sería printf 'Hello\n\n'.

Si su objetivo es imprimir, Hello\incluida la barra diagonal inversa, seguida de una nueva línea adicional , entonces el enfoque con comillas dobles es posible pero engorroso. Para averiguarlo, al revés de trabajo: echo -econvertidos \\a \y \na una nueva línea, y los convertidos de doble citando \\a \, para que pueda hacerlo con seis barras invertidas ( echo -e "Hello\\\\\\n"), ya que \\nse convierte en \ndebido a una barra invertida de escape otra. También puede hacerlo con cinco, porque las comillas dobles se conservan \ncuando \no se escapa.

Esto ilustra el beneficio de echo -elas comillas simples: simplemente ponga lo que quiera ver dentro de las comillas simples ( echo -e 'Hello\\\n'). printfTambién es bueno aquí. Una opción es printf 'Hello\\\n\n'. Pero lo que printfrealmente brilla es que puedes conectar argumentos adicionales. Puede usar printf '%s\n\n' 'Hello\', que inserta el segundo argumento (literalmente Hello\porque las comillas simples no cambian nada) en lugar de %s.

Eliah Kagan
fuente