Quotes, variable expansion, wildcards, and everything else mentioned in the bash manual section on expansion is handled by bash.
For example, when you run the bash command
echo "x is: $x", bash parses this to find out that it needs to run the command
echo with one argument which is
x is: 12345. Given
echo "x is" "$x", bash runs
echo with two arguments:
x is and
12345 — this is why the two spaces inside the quotes are preserved (they're part of the argument which echo prints unmodified), but the two spaces outside the quotes are not (for the shell, two spaces to separate arguments are as good as a single one, and
echo always prints a single space in between).
echo command (or any other command) has no way to know which shell command produced the argument
x is: 12345, or indeed whether a shell was involved at all. Here are a few sample commands that produce this argument:
echo "x is: 12345"
echo 'x is: 12345'
echo x\ is:\ 12345
echo "x is: $x"
echo 'x is:'\ "$x"
echo "$(echo "x ")is: $x"
# Assume there is no other file whose name begins with x in the current directory
touch "x is: $x"; echo x*
Or it could be
exec "echo", "x is: 12345" in Perl, or
execlp("echo", "echo", "x is: 12345") in C, etc.
This holds for every command. And the same principle holds for other shells, although they each have a slightly (or significantly) different set of expansions.
On the other hand, options are handled by the command. For example,
ls -l -t and
ls -l "-t" in bash (or any similar shell) both run
ls in exactly the same way, with the two arguments
-t. This is why no form of shell quoting won't help you if you want to run
ls to display information about a file called
-t. You can do that with
ls -l -- -t, i.e. by passing
-- as an argument. This is a convention followed by most commands: nothing after
-- is parsed as an option. Once again, this is a feature of the command; for the shell, a leading dash is nothing special.
One thing that can get tricky is backslashes. In bash and other shells, backslash outside of any quotes means that the next character loses its special meaning. For example,
echo \"x\ is:\ 12345\" prints
"x is: 12345", because each of the characters that are preceded by a backslash lose their special meaning (quote syntax for
", word separator for spaces). But some commands also interpret backslashes. When they do, you need to ensure that the backslash gets to them. For example, in bash, the
echo command prints backslashes literally by default, but if you pass the option
-e or run
shopt xpg_echo first, then
echo has its own escape sequences (this is for bash, the
echo command in different shells and on different systems have different rules about whether they treat backslashes specially). For example,
echo 'a\nb' prints
echo -e 'a\nb' prints
\n means “newline” to
echo -e. On the other hand,
echo a\nb prints
\n is expanded by the shell and there
\ means “quote the next character”.
Also, be careful when multiple shells are involved, e.g. with SSH. When you run
ssh in a shell, the local shell parses the command as usual. The SSH client joins its non-option arguments with spaces in between, and sends the resulting string to the SSH server. The SSH server passes this string to the remote shell. This means that there are two full rounds of shell expansion between what you type in a terminal or in a shell script, and what gets executed on the remote machine.