If you're building compound commands, running redirections, etc., then you need to use eval:
A="test; ls"
eval "$A"
However, it's far better not to do this. A typical use case that follows good practices follows:
my_cmd=( something --some-arg "another argument with spaces" )
if [[ $foo ]]; then
my_cmd+=( --foo="$foo" )
fi
"${my_cmd[@]}"
Unlike the eval version, this can only run a single command line, and will run it exactly as-given -- meaning that even if foo='$(rm -rf /)' you won't get your hard drive wiped. :)
If you absolutely must use eval, or are forming a shell command to be used in a context where it will necessarily be shell-evaluated (for instance, passed on a ssh command line), you can achieve a hybrid approach using printf %q to form command lines safe for eval:
printf -v cmd_str 'ls -l %q; exit 1' "some potentially malicious string"
eval "$cmd_str"
See BashFAQ #48 for more details on the eval command and why it should be used only with great care, or BashFAQ #50 for a general discussion of pitfalls and best practices around programmatically constructing commands. (Note that bash -c "$cmd_str" is equivalent to eval in terms of security impact, and requires the same precautions to use safely).
;to be honored, you need to useeval, and usingevalis prone with security risks if not done with great care.