Start with a simpler comparison:
$ echo '\\abc'
$ echo \\abc
In the first command, the apostrophes do not become part of the argument to
echo because they have been used for quoting. All of the characters inside, including both backslashes, are passed to
In the second command, the first backslash quotes the second backslash. The one that was used for quoting does not become part of the argument to
echo. The other one is passed to
echo, along with the
abc (which was not quoted, but that doesn't matter because they are not metacharacters).
Now we're ready to talk about your command sequence
$ echo $va
When the assignment command is executed, the apostrophes quote everything between them. The apostrophes do not become part of the value assigned, but everything else does, including both backslashes.
echo command, there are no quoting characters. The value of
va is retrieved and inserted into the argument list. Now there is an argument containing 2 backslashes, but they don't function as quoting characters, because the parsing phases where we were looking for quoting characters was done before variable expansion.
Variable expansion is not like macro expansion. The resulting series of arguments is not fed back in to the full command line parser. Some post-processing is done (word-splitting and globbing) but there is not a second pass of quote removal and variable expansion.
When you want to build an argument list and reparse the whole thing as a new command line with all shell features available, you can use
eval. This is usually a bad idea because "all shell features" is a lot, and if you aren't careful, something bad can happen.
$ eval echo $va
$ va='\\abc;rm -rf $important_database'
$ eval echo $va
When you find yourself wanting to use shell quoting syntax inside the value of a shell variable, try to think of a different way to solve your problem.