bashcolorsvariable-expansion

How can I display the colors of text inserted with color codes by another program in Bash?


When the text directly contained color code for example:

a="\033[0;31mRED\033[0m"
echo -e $a

The terminal had no problem colorizing the text in red. But when I modified the color code indirectly:

#!/bin/bash

# define color mappings
declare -A colors=(
    ['r']='\033[0;31m'  # Red (escaped for sed/printf)
    ['reset']='\033[0m'  # Reset color
)

# Sample text
t="abc def [ghi] jkl
nmo [ttt] dfd
and more"
# colorize all [...] in red
echo -e "$t" | sed "s/\(\[[^]]*\]\)/\\${colors[r]}\1\\${colors[reset]}/g"

The result was

abc def \033[0;31m[ghi]\033[0m jkl
nmo \033[0;31m[ttt]\033[0m dfd
and more

The terminal did not colorize [...]s with red color at all but showed the raw color codes. It seems like the problem is related to the timing of variable expansion of some sort.


Solution

  • The problem is not in variable expansion. The problem is you need echo -e to interpret the colour codes, but you run echo -e only for the original string. You then insert the colour codes, but this doesn't go through echo -e anymore. So, one way is to add it:

    echo -e $(echo "$t" | sed "s/\(\[[^]]*\]\)/\\${colors[r]}\1\\${colors[reset]}/g" )
    

    You can also store directly the colour codes, not their escaped variant. Then, you can directly output them without needing -e:

    declare -A colors=(
        ['r']=$'\033[0;31m'   # <- See the dollar sign?
        ['reset']=$'\033[0m'  # <- It interprets the escape sequences.
    )
    

    The rest of the script can stay as it was, but you don't need -e for the output:

    echo "$t" | sed "s/\(\[[^]]*\]\)/\\${colors[r]}\1\\${colors[reset]}/g"