Bash color output fails

sed doesn't treat \e as an escape sequence. With GNU sed, and most other sed implementations out there, \e in an s replacement text just means e. The only backslash escapes you can use portably in s replacement text are \\ to mean a backslash, \& to mean a literal &, \/ (where / is the delimiter character) for a literal /, and \1 through \9 for backreferences. GNU sed and BusyBox (but not e.g. OpenBSD sed) adds \n for a newline. Thus the output of your sed command has a literal e.

In bash, you can easily put a literal escape character in your variables from the start. \e is one of the escape sequences recognized by the $'…' construct.

ColorOff=$'\e[0m'       # Text Reset
BWhite=$'\e[1;37m'      # Bold White

There are two problems in your echo command.

I expanded the variables for brevity.

$ echo -e "test TEST test" | sed -e "s/TEST/\e[1;37mTEST\e[0m/g"
test e[1;37mTESTe[0m test

First problem: the backslashes are lost somewhere between sed magic and shell magic. You have to escape them.

$ echo -e "test TEST test" | sed -e "s/TEST/\\e[1;37mTEST\\e[0m/g"
test e[1;37mTESTe[0m test

Still doesn't work. Maybe more escaping?

$ echo -e "test TEST test" | sed -e "s/TEST/\\\e[1;37mTEST\\\e[0m/g"
test \e[1;37mTEST\e[0m test

Finaly the backslashes are coming through. I have no idea why we need three backslashes, that is some weird sed magic.

Second problem: the echo -e is pointless. -e enables interpretation of backslash escapes, but all echo -e gets to interpret is "test TEST test". The backslash escapes are coming from sed, which does not care about them and prints them raw.

What you want is this:

$ echo -e $(echo "test TEST test" | sed -e "s/TEST/\\\e[1;37mTEST\\\e[0m/g")
test TEST test

with bold TEST in output.

Here is the full script with the changes:

#!/bin/bash

ColorOff='\\\e[0m'       # Text Reset
BWhite='\\\e[1;37m'      # Bold White

string="test TEST test"
echo -e $(echo "$string" | sed -e "s/TEST/${BWhite}TEST${ColorOff}/g")

Tags:

Bash

Sed

Quoting