Bash – Understanding Carriage Return Behavior

bashnewlinesshell-scriptspecial characters

I have one quick question.
Is it normal that bash (i am using 4.4.11) is not displaying lines/text that is separated / end with plain \r ?

I was a bit surprised to see this behavior:

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

But "hello again" text is still there,somehow "hidden":

$ 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

And as soon as we just play with bash is fine…. But is this a potential security risk? What if contents of variable "a" come from outter world and include "bad commands" instead of just hello?

Another test, a bit unsecure this time:

$ 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 a hidden rm instead of a hidden ls.

Same behavior when using echo -e:

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

Is it me that does something wrong…?

Best Answer

Your echo "$a" prints "hello", then goes back to the beginning of the line (which is what \r does), print "again", goes back again, prints "george", goes back again, and goes to the next line (\n). It’s all perfectly normal, but as chepner points out, it doesn’t have anything to do with Bash: \r and \n are interpreted by the terminal, not by Bash (which is why you get the full output when you pipe the command to od).

You can see this better with

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

since that will leave the end of the overwritten text:

georgen,o

You can’t really use that to hide commands though, only their output (and only if you can be sure to overwrite with enough characters), unless using eval as you show (but using eval is generally not recommended). A more dangerous trick is using CSS to mask commands intended to be copied and pasted from web sites.

Related Question