BASH y comportamiento de retorno de carro

11

Tengo una pregunta rapida.
¿Es normal que bash (estoy usando 4.4.11) no muestra líneas / texto que está separado / finaliza con plain \r?

Me sorprendió un poco ver este comportamiento:

$ a=$(printf "hello\ragain\rgeorge\r\n")
$ echo "$a"
george

Pero el texto "hola de nuevo" sigue ahí, de alguna manera "oculto":

$ echo "$a" |od -w32 -t x1c
0000000  68  65  6c  6c  6f  0d  61  67  61  69  6e  0d  67  65  6f  72  67  65  0d  0a
          h   e   l   l   o  \r   a   g   a   i   n  \r   g   e   o   r   g   e  \r  \n

Y tan pronto como juguemos con bash está bien ... ¿Pero es esto un riesgo potencial de seguridad? ¿Qué sucede si los contenidos de la variable "a" provienen de un mundo externo e incluyen "comandos incorrectos" en lugar de solo hola?

Otra prueba, un poco insegura esta vez:

$ a=$(printf "ls;\rGeorge\n")
$ echo "$a"
George
$ eval "$a"
0                   awkprof.out       event-tester.log  helloworld.c      oneshot.sh         rightclick-tester.py  tmp                    uinput-simple.py
<directory listing appears with an error message at the end for command George>

Imagine un oculto en rmlugar de un oculto ls.

Mismo comportamiento cuando se usa echo -e:

$ a=$(echo -e "ls;\rGeorge\r\n"); echo "$a"
George

¿Soy yo quien hace algo mal ...?

George Vasiliou
fuente

Respuestas:

20

Sus echo "$a"impresiones "hola", y luego regresa al principio de la línea (que es lo que \rhace), se imprime "nuevo", se remonta de nuevo, impresiones de "George", se remonta de nuevo, y va a la siguiente línea ( \n). Todo es perfectamente normal, pero como señala Chepner , no tiene nada que ver con Bash: \ry \nson interpretados por el terminal, no por Bash (por lo que obtienes la salida completa cuando canalizas el comando od).

Puedes ver esto mejor con

$ a=$(printf "hellooooo\r  again,\rgeorge\r\n")
$ echo "$a"

ya que eso dejará el final del texto sobrescrito:

georgen,o

Sin embargo, realmente no puede usar eso para ocultar comandos, solo su salida (y solo si puede asegurarse de sobrescribir con suficientes caracteres), a menos que use evalcomo se muestra (pero evalgeneralmente no se recomienda usar ). Un truco más peligroso es usar CSS para enmascarar comandos destinados a ser copiados y pegados desde sitios web.

Stephen Kitt
fuente
Lo suficientemente claro, gracias. Tuve suerte / mala suerte de usar una última palabra en mi prueba capaz de sobrescribir completamente las dos palabras anteriores.
George Vasiliou
2
Tenga en cuenta que esto no tiene nada que ver bash, sin embargo; depende completamente de la terminal cómo "mostrar" el retorno de carro, o cómo mostrar los caracteres sobrescritos. Por ejemplo, sería perfectamente válido que un terminal se muestre -\r|como algo parecido a un signo más, en lugar de solo una tubería.
chepner el
@chepner ¡Es bueno saberlo! Gracias por compartir. Pensé que esto era solo un comportamiento bash.
George Vasiliou
@GeorgeVasiliou Nope, bashsolo escribe bytes en un archivo; depende de quien lea esos bytes interpretarlos.
chepner
Nitpick: printf, que es una fiesta de comando integrado (aunque también existe como un archivo ejecutable independiente), interpreta la \r(una secuencia de dos bytes: 0x5cy 0x72y produce el retorno de carro (un solo byte: 0x0d.) Entonces, sí, el terminal interpreta el byte 0x0dde una manera especial, pero no interpreta la cadena original \r.
Suzanne Dupéron
6

En el mundo de Unix, un retorno de carro (comúnmente codificado como \ren lenguajes de programación) es un carácter de control sin complicaciones. Puede tener retornos de carro dentro de una línea de texto, como cualquier otro carácter aparte de un avance de línea (también llamado nueva línea ), que marca el final de una línea.

En particular, en un script bash, un retorno de carro es un carácter constitutivo de una palabra ordinaria, como letras y dígitos. Cualquier efecto especial del retorno de carro proviene del terminal, no del shell.

Un retorno de carro es un personaje de control . Cuando lo imprime en un terminal, en lugar de mostrar un glifo , el terminal realiza algún efecto especial. Para un retorno de carro, el efecto especial es mover el cursor al comienzo de la línea actual. Por lo tanto, si imprime una línea que contiene un retorno de carro en el medio, el efecto es que la segunda mitad se escribe sobre la primera mitad.

Varios otros caracteres de control tienen efectos especiales: el carácter de retroceso mueve el cursor una posición hacia la izquierda. El carácter de campana hace que el terminal emita un sonido o atraiga la atención del usuario. El personaje de escape comienza una secuencia de escape que puede tener todo tipo de efectos especiales.

Si muestra una salida no confiable, debe restregar o escapar de los caracteres de control. No solo retorna el carro, sino también varios otros, en particular el carácter de escape, que puede causar todo tipo de efectos negativos. Consulte ¿Puede "capturar" un archivo un riesgo potencial de seguridad? y ¿Cómo evitar ataques de secuencia de escape en terminales? para más sobre el tema

Gilles 'SO- deja de ser malvado'
fuente
0

Puede ver los retornos de carro en una variable bash utilizando la printffunción con un %qformato.

$ TESTVAR="$(printf ' Version: 1 \r Build: 20180712 \r Test: 1324')"

$ printf %q $TESTVAR
Version:1$'\r'Build:20180712$'\r'Test:1324

Fuentes y lecturas adicionales:

nuwandame
fuente