Is it possible to use ANSI color escape codes in Bash here-documents?

In your script, these assignments

normal='\e[0m'
yellow='\e[33m'

put those characters literally into the variables, i.e., \e[0m, rather than the escape sequence. You can construct an escape character using printf (or some versions of echo), e.g.,

normal=$(printf '\033[0m')
yellow=$(printf '\033[33m')

but you would do much better to use tput, as this will work for any correctly set up terminal:

normal=$(tput sgr0)
yellow=$(tput setaf 3)

Looking at your example, it seems that the version of printf you are using treats \e as the escape character (which may work on your system, but is not generally portable to other systems). To see this, try

yellow='\e[33m'
printf 'Yellow:%s\n' $yellow

and you would see the literal characters:

Yellow:\e[33m

rather than the escape sequence. Putting those in the printf format tells printf to interpret them (if it can).

Further reading:

  • tput, reset - initialize a terminal or query terminfo database
  • printf - write formatted output (POSIX)

This assignments are not placing escaped characters in the variable:

normal='\e[0m'                  yellow='\e[33m'

To do so, you need echo -e printf or $'...' (in bash).

Since you are using bash, you might as well use this:

normal=$'\e[0m'                 yellow=$'\e[33m'

Please note the $ before the string '\e[0m'.

However, the portable way to get escaped characters is printf, as this:

normal="$(printf '\033[0m')"    yellow="$(printf '\033[33m')"

The octal value (033) of the escape character is valid in all POSIX shells.