As has been said already, your code fails in this specific case because bash makes a variable (as if the command) local (has been issued) when declare is used. That is equivalent to ksh's typeset, as well as zsh's typeset, and its alternative forms declare, integer, local and readonly (but not export).
Also, you are trying to print via an indirect form echo "${!foo}". That will not print the value of $foo but the value of a variable (if it exists) which name is the value of $foo.
Using declare inside the function is possible if this form is used (for bash 4.2+):
declare -g "$1"="[ \033[00;32m$2 OK\033[0m ]"
The most basic way to make the assignment without using declare for older bash version (and in general for most shells) is the always worrisome eval (if the value of $1 or $2 has any chance of having been set by an attacker (or external user)):
eval "$1"='"[ \033[00;32m'"$2"' OK\033[0m ]"'
Of course, that will assign the string [ \033[00;32mbar OK\033[0m ] to $foo, which doesn't seem to be the intended goal.
This simple change should correctly assign the intended escaped characters to the variable:
eval "$1"=$'"[ \033[00;32m'"$2"$' OK\033[0m ]"'
Which will change to Green for bar OK and then reset the color setting.
To remove the risk of eval, we need to use something else.
For ksh 93+ and bash 4.3+ we may use namerefs (bash form used):
declare -n ref=$1
ref=$'"[ \033[00;32m'"$2"$' OK\033[0m ]"'
Or bash printf's -v option:
printf -v "$1" '"[ \033[00;32m%s OK\033[0m ]"' "$2"
In which case the interpretation of the escape codes (\033) is done by printf.
Once the variable contains the required value, is better to use printf to print it instead of echo, and no indirection is needed:
#!/bin/bash
format_msg() {
printf -v "$1" '"[ \033[00;32m%s OK\033[0m ]"' "$2"
}
format_msg "foo" "bar"
printf 'var foo=%s\n' "${foo}"